SPOSERV

AI로 연동 코드 만들기

API 정의와 사용 예시를 UTF-8 Markdown으로 받으세요.

예제의 YOUR_API_KEY 자리에 가입 후 발급되는 API 키를 넣으세요.

시작하기

회원 데이터 조회는 GET이며 JSON을 돌려줍니다. 팀·리그·북메이커·마켓 등 모든 이름은 원문과 한글명(*_ko)을 함께 제공합니다. 베이스 URL은 다음과 같습니다.

https://sposerv.com/api/v1

첫 호출로 계정 정보를 확인해 보세요 (무료).

curl -s "https://sposerv.com/api/v1/me" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/me", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/me");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/me"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/me",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/me");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));

북메이커별 수집 통계

북메이커별 상세 수집 통계는 관리자 전용 화면에서 제공합니다. 회원 API에서 제공하는 북메이커 목록과 이름은 /api/v1/reference/bookmakers로 조회하세요.

종목별 경기 요약은 /api/v1/sports, 데이터의 최근 갱신 상태는 /api/v1/health에서 확인할 수 있습니다. 회원 API 키와 유효한 이용권이 필요하며 성공한 요청마다 호출 1회를 사용합니다.

인증과 이용 기간

  • 인증은 요청 헤더 X-API-Key: <키>로 합니다. 헤더를 쓸 수 없는 환경에서는 Authorization: Bearer <키> 또는 쿼리 ?api_key=<키>도 됩니다. URL은 프록시·브라우저 기록 등에 남을 수 있으므로 헤더를 권장합니다 (마이페이지 사용 내역에는 키를 기록하지 않습니다).
  • 키는 마이페이지에서 언제든 재발급할 수 있으며, 재발급 즉시 이전 키는 거부됩니다.
  • 라이브 7일 이용권: 280 USDT, 500,000회. 마이페이지에서 USDT 잔액으로 구매하며 관리자 무상 지급도 가능합니다.
  • 라이브 30일 이용권: 1,000 USDT, 2,200,000회. 마이페이지에서 USDT 잔액으로 구매하며 관리자 무상 지급도 가능합니다.
  • 이용 중 추가 구매하면 현재 종료일에 선택한 7일 또는 30일이 더해지고 해당 요금제의 호출 한도가 추가됩니다. 이미 사용한 호출 수는 유지됩니다. 만료되었거나 라이브 이용권이 없으면 구매 시점부터 시작합니다. 같은 구매 요청의 재전송은 한 번만 처리합니다.
  • 개발용 이용권: 계정당 최초 1회, 신청 시점부터 정확히 7일. 실제 데이터가 아닌 가공 데이터(가상 경기·가공 배당·가공 결과)만 제공합니다. 모든 응답에 meta.mode = "development", meta.synthetic = true, meta.notice와 헤더 X-Data-Mode: development, X-Data-Notice가 붙으므로 이 값으로 개발 데이터가 운영 화면이나 정산에 섞이지 않게 차단하세요. 관리자 기간 연장이 가능합니다. 라이브 이용권이 있으면 라이브가 우선이며 개발 기간은 계속 흐릅니다.
  • 활성 이용권이 없으면 첫 데이터 호출에서 잔액으로 라이브 7일 이용권을 구매할 수 있습니다. 개발 기간에는 자동 구매하지 않으며 마이페이지에서 직접 시작할 수 있습니다. 만료 후 잔액이 충분하면 7일 이용권을 다시 구매합니다. 자동 구매는 조회 파라미터 검증보다 먼저 처리되므로 호출 전 /me에서 이용 상태를 확인하세요. 30일 이용권은 마이페이지에서 직접 구매하세요.
  • /me는 이용권 없이 조회할 수 있습니다. 다른 엔드포인트는 이용권이 필요하며 성공한 응답마다 1회 사용합니다. 오류는 사용량에 포함하지 않습니다. 한도 소진 시 조기 자동 구매나 초과 요금은 없습니다.
  • /me의 balance_usdt, subscription으로 잔액·구분·남은 시간·호출량을 확인하세요. 응답 meta.mode와 X-Data-Mode는 development/live/none입니다.
  • 계정 전체 API 요청은 최소 5초 간격입니다. 범위 조회는 최대 10개 종목, 24시간이며 경기·결과는 최대 100개, 배당은 500개 가격 행입니다. 응답 상한은 2 MiB입니다. 다음 페이지는 5초 후 요청하세요.
  • 429를 받으면 Retry-After 헤더의 초만큼 기다린 뒤 다시 요청하세요. 거절된 요청도 분당 요청 수에 포함되므로 기다리지 않고 재시도하면 계속 거절됩니다. 한 계정이 1분에 30회를 넘게 보내면 그 분의 나머지 요청은 모두 429이고, 이런 요청이 이어지면 보낸 IP가 5분간 차단됩니다.
  • 기간 전체를 받는 스냅샷 시작은 계정당 시간당 60회입니다. 한 번 받은 뒤에는 snapshot=0&updated_since_ts=…로 변경분만 받으세요.

응답 형식 · 오류

성공:

{ "ok": true, "data": { ... }, "meta": { "endpoint": "events", "mode": "live", "development": false, "calls_remaining": 499999, "server_time_ts": 1790250228 } }

개발용 이용 기간(가공 데이터):

{ "ok": true, "data": { ... }, "meta": { "endpoint": "events", "mode": "development", "development": true, "synthetic": true, "notice": "개발용 가공 데이터입니다. 실제 경기·배당·결과가 아니므로 서비스에 사용할 수 없습니다.", "notice_en": "Synthetic development data: not real fixtures, odds or results.", "calls_remaining": 120959, "server_time_ts": 1790250228 } }

실패:

{ "ok": false, "code": "subscription_required", "error": "subscription_required" }
HTTPcode의미
401unauthorizedAPI 키가 없거나 틀림
402subscription_required유효 이용권과 구매 잔액이 부족합니다. 마이페이지에서 USDT로 충전하세요.
429subscription_quota_exceeded현재 이용권의 호출 한도 소진. me에서 expires_at을 확인하세요.
403forbidden차단된 계정
404not_found엔드포인트 또는 event_id 없음
405method_not_allowedGET만 지원
409subscription_changed요청 처리 중 이용 구분 또는 이용권이 변경됨. 5초 후 다시 요청하세요.
409page_out_of_order목록의 페이지는 같은 파라미터로 1부터 순서대로 요청해야 합니다(마지막으로 받은 페이지 재요청은 가능). page=1부터 다시 시작하세요.
422snapshot_requiredupdated_since_ts가 3600초보다 오래됨. snapshot=1로 전체를 다시 받은 뒤 변경분 조회를 이어가세요.
429snapshot_limit_exceeded시간당 스냅샷 시작 한도 초과. Retry-After 초 뒤에 다시 시작하거나 snapshot=0 변경분 조회를 사용하세요.
413response_too_large응답 2 MiB 초과. 기간·종목·limit을 줄이세요.
422validation_failed파라미터 형식 오류 (error에 이유)
429rate_limited5초 간격 또는 분당 요청 한도 초과. Retry-After 초 뒤 재시도하세요. 거절된 요청도 분당 요청 수에 포함됩니다.
503query_timeout조회가 서버 제한 시간을 넘김. 호출량은 차감되지 않습니다. 기간·종목·필터를 좁혀 Retry-After 초 뒤 다시 요청하세요.
500internal서버 오류. 호출량은 차감되지 않음

시각: *_ts는 unix 초(UTC), *_at 문자열은 KST(UTC+9)입니다. 배당은 소수 셋째 자리까지의 십진 배당(decimal odds)입니다.

인코딩: JSON은 application/json; charset=UTF-8입니다. 한글은 UTF-8로 처리하고 query 값은 URL 인코딩하세요. 날짜의 공백과 +09:00도 인코딩합니다. 소스·저장 파일은 UTF-8을 사용하세요. 예시 보기

한글명 제공 (원문명 · 한글명)

모든 이름은 원문과 한글명을 함께 제공합니다. 원문 필드는 그대로 두고 같은 자리에 *_ko 필드가 추가됩니다. 기본으로 데이터 응답에 포함되며 호출량은 늘지 않습니다. include_names=0으로 보강을 생략할 수 있습니다.

대상원문 필드한글명 필드예
종목sport_key / sport_namesport_name_kofootball → 축구
국가 · 리그 · 라운드country_name, tournament_name, tournament_stage_namecountry_name_ko, tournament_name_ko, tournament_stage_name_koPremier League → 프리미어리그
홈 / 원정 팀 · 선수home_name, away_namehome_name_ko, away_name_koArsenal W → 아스널 W, Alcaraz C. → C. 알카라스
경기장venuevenue_koAnfield, Liverpool, England → 안필드, 리버풀, 잉글랜드
북메이커bookmakerbookmaker_kobet365 → 벳365
마켓 · 구간market, periodmarket_ko, period_koOver/Under → 오버/언더, 1st Half → 전반
결과 선택지outcome_labels[]outcome_labels_ko[]["1","X","2"] → ["홈 승","무승부","원정 승"]
경기 단계event_stage_name, periods[].nameevent_stage_name_ko, periods[].name_koAfter Penalties → 승부차기 후 종료
혼합 파라미터mixed_parameter_namemixed_parameter_name_ko
이름 사전name, short_namename_ko, short_name_ko/reference/*
  • 미번역은 null입니다. 새로 수집된 팀·선수 이름은 번역되기 전까지 잠시 null일 수 있으므로 name_ko ?? name처럼 원문으로 대체해 표시하세요. 원문을 한글명 자리에 대신 채워 보내지 않습니다.
  • 식별에는 ID와 원문을 쓰세요. 한글명은 표시용이며 오탈자 수정 등으로 바뀔 수 있습니다. 경기는 event_id, 북메이커·마켓·구간은 provider_id·betting_type_id·scope_id로 구분하세요.
  • outcome_labels_ko는 outcome_labels와 순서·길이가 같습니다. odds[i] ↔ outcome_labels[i] ↔ outcome_labels_ko[i].
  • 팀·리그·라운드 이름은 종목별로 번역됩니다. 같은 철자라도 종목이 다르면 다른 팀일 수 있습니다.
  • 표기 규칙: 여자팀·연령별·2군은 원문 접미사를 유지합니다(W, U20, B, II). 선수는 이니셜. 성(C. 알카라스), 복식은 /로 연결합니다. 약어만으로 된 팀명(HIFK, LSU)은 약어 그대로입니다.
  • 한글로 검색: /events?q=아스널처럼 q에 한글을 넣으면 한글명으로도 찾습니다.
  • 사전 일괄 받기: /reference/names로 종류·종목별 원문/한글명 전체를 받을 수 있고, updated_since_ts로 수정분만 동기화할 수 있습니다.
  • 개발용 이용 기간의 응답은 가상 한글명(개발용 팀 12 등)이며 실제 사전을 조회하지 않습니다.
운영자 전용: 사전 관리 API

한글명 사전은 운영자가 관리합니다. 사전 관리 API와 명령 도구는 회원 API 키가 아닌 별도 운영자 키(X-Dictionary-Key 또는 Bearer)를 사용하며 이용권·호출량과 무관합니다. 분당 30회, 요청 본문 1 MiB, 업데이트 최대 500행입니다.

메서드 / 경로용도
GET /api/v1/dictionary사전 조회. entity_type, sport_key, untranslated=1, limit(최대 500), after. 응답 next_after가 null이면 마지막 페이지.
GET /api/v1/dictionary/export기존 데이터를 사전에 동기화한 뒤 JSONL·SQL·manifest·설명 파일을 ZIP으로 다운로드. entity_type, sport_key, untranslated 필터 지원.
POST /api/v1/dictionary/sync기존 원문 이름 동기화. 한글명과 revision은 보존.
POST /api/v1/dictionaryJSON entries의 id, revision, name_ko로 번역 업데이트. dry_run=true로 롤백 검증.
{ "entries": [{ "id": "다운로드한 64자리 id", "revision": 1, "name_ko": "한글 이름" }], "dry_run": true }

Content-Type: application/json으로 전송하세요. 원문·ID·revision은 수정하지 않습니다. 검증 후 dry_run: false로 반영합니다. 한 배치는 전체 성공 또는 전체 롤백합니다. 다른 수정과 충돌하면 409를 반환하므로 최신 사전을 다시 받으세요. name_ko: null 또는 빈 문자열은 번역 삭제입니다. 수집기는 기존 번역을 덮어쓰지 않으며 수정 내용은 다음 회원 API 응답부터 반영됩니다.

스냅샷과 변경분 조회

경기·결과·배당 목록(/events, /results, /odds)은 두 가지 방식으로 받습니다. 처음 한 번 스냅샷으로 전체를 받고, 그다음부터는 바뀐 것만 받는 방식을 권장합니다.

방식파라미터돌려주는 것한도
스냅샷snapshot=1 (기본값)기간 안의 전체 데이터시작(page=1)은 계정당 시간당 60회. 이어지는 페이지는 포함하지 않음
변경분snapshot=0&updated_since_ts=…기준 시각 이후 수정된 것만스냅샷 한도와 무관 (일반 호출량·5초 간격만 적용)
# 1) 원하는 경기 날짜를 먼저 전체 조회 (날짜는 예시)
GET /api/v1/odds?sports=football&date=2026-10-06&limit=500
    → query_id: "…", next_page: 2, sync_complete: false, checkpoint_ts: null
GET /api/v1/odds?sports=football&date=2026-10-06&limit=500&page=2&query_id=…
    → next_page: null, sync_complete: true, checkpoint_ts: …

# 2) 변경분: 직전 완료된 조회의 checkpoint_ts를 사용 (경기 날짜 제한 없음)
GET /api/v1/odds?sports=football&all_dates=1&limit=500&updated_since_ts=…
    → 모든 페이지를 받은 뒤 새 checkpoint_ts 저장

# 3) 기준일시를 직접 입력할 수도 있습니다. 아래 시각을 현재 기준 최근 1시간 안으로 바꾸세요.
curl -G 'https://sposerv.com/api/v1/events' -H 'X-API-Key: YOUR_API_KEY' \
  --data-urlencode 'sports=football' --data-urlencode 'all_dates=1' \
  --data-urlencode 'updated_since=2026-10-06 09:00:00' \
  --data-urlencode 'include_total=0' --data-urlencode 'include_result=0'
  • 기준일시 — updated_since_ts는 unix 초, updated_since는 KST YYYY-MM-DD HH:MM:SS 또는 2026-10-06T09:00:00+09:00 같은 RFC3339입니다. 둘 중 하나만 보내세요. 공백과 +는 URL 인코딩합니다. 시작·종료 초 모두 포함합니다. 최근 60분을 벗어난 기준이면 422 snapshot_required이므로 전체 조회를 다시 받으세요.
  • 종료 시각 — 기본 updated_until_ts는 첫 페이지 요청 시각으로 고정됩니다. 변경분은 updated_until_ts 또는 updated_until로 종료 기준을 직접 정할 수도 있습니다. 시작 기준 이상·현재 이하만 가능합니다. 날짜를 지정한 과거 상태를 복원하는 기능은 아닙니다.
  • 조회 완료 — sync_complete=true일 때만 checkpoint_ts를 저장합니다. 이 값은 종료 기준에서 30초를 뺀 값입니다. next_updated_since_ts는 기존 연동용으로 남으며 완료 전에는 다음 조회 기준으로 쓰지 마세요. narrow_range_required=true이면 기간·종목·필터를 나누어 끝까지 받으세요.
  • 페이지 순서 — 첫 응답의 query_id와 같은 필터·limit·시작/종료 기준을 유지하고 next_page를 순서대로 요청하세요. 마지막으로 받은 페이지 재요청은 가능하지만 응답 행은 그동안 수정될 수 있습니다. 건너뛰기·필터 변경·다른 계정의 식별값·1시간 이상 중단은 409 page_out_of_order입니다. 같은 조건을 동시에 조회해도 식별값으로 구분됩니다. 기존 식별값 없는 연동은 해당 조건의 가장 최근 조회를 잇기 때문에 병렬로 사용하지 마세요.
  • 경기 날짜 — 기본은 KST 날짜 또는 최대 24시간 킥오프 구간입니다. 변경분의 all_dates=1은 경기 날짜와 무관하게 저장된 데이터의 최근 변경을 찾습니다. 일정이 다른 날짜로 옮겨진 경기나 이전 경기 결과 정정을 받을 때 사용하세요. 이때 date/from_ts/to_ts를 빼고 sports는 유지합니다. 개발용은 7일 범위의 구성된 경기로 동작합니다.
  • 덮어쓰기 — 겹치는 구간은 같은 행을 다시 반환합니다. 경기는 event_id, 결과는 event_id, 배당은 event_id + betting_type_id + scope_id + handicap_type_id + handicap_value + mixed_parameter_id + provider_id로 덮어쓰세요. 엔드포인트·종목·필터별로 기준을 따로 저장하고 실패한 조회에서는 기준을 이동하지 마세요.
  • 변경 기준 — 경기: 이름·일정·상태·경기 단계·우선순위·경기장·결과 요약. 결과: 스코어·상태·구간. 배당: 새 가격·가격 변경·철회. 배당 갱신만으로 경기의 changed_at은 갱신되지 않으므로 가격은 /odds로 받으세요. 철회된 배당은 active:false이며 로컬 활성 가격에서 제거합니다. 변경분에서 active_only=1이면 철회를 놓칩니다. 번역 수정은 /reference/names로 따로 동기화합니다.
  • 조회 범위와 동시 수정 — 현재 저장된 행을 읽으며, 불변 스냅샷이나 모든 중간 변경 이력은 아닙니다. 페이지를 받는 동안 행이 수정·이동될 수 있으므로 전체 조회 후 변경분을 이어 받고 주기적으로 전체 데이터를 대조하세요. 30초를 넘는 저장 지연, 보존 기간에 따른 삭제, 필터 밖으로 이동한 행의 삭제 알림은 보장하지 않습니다. 동기화에는 state/final_only 같은 변하는 필터를 가급적 빼세요.
  • 선택과 응답 크기 — 세 목록 모두 event_ids(최대 100개), tournament_ids(최대 50개), country, state, priority, q, has_odds를 지원합니다. 경기·결과에서 include_total=0이면 건수 집계를 생략하고 total=null, 경기에서 include_result=0이면 result를 생략합니다. include_names=0이면 한글명 보강을 생략합니다. 기본 응답 필드는 유지됩니다.
  • 한도 — 각 페이지는 호출 1회이며 최소 5초 간격입니다. 스냅샷 시작 한도 초과는 429 snapshot_limit_exceeded와 Retry-After를 반환하고 호출량을 차감하지 않습니다. /me에서 사용량을 확인하세요. 단일 경기 조회는 스냅샷 한도와 무관합니다.
  • 배당사 선택 — /odds, /events/{id}/odds, /events/{id}/odds/history에서 provider_ids=417,16 또는 bookmakers=bet365,1xbet을 사용합니다. 최대 50개이며 provider_id와 합쳐집니다.
GET /api/v1/me 무료

내 계정 / 이용 기간

USDT 잔액(balance_usdt), 이용 구분·만료 시각·남은 시간·호출량(subscription)을 돌려줍니다. 이용권 없이 조회 가능합니다.

파라미터형식필수설명
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/me
curl -s "https://sposerv.com/api/v1/me" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/me", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/me");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/me"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/me",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/me");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "email": "[email protected]",
        "balance_usdt": "0.000000",
        "subscription": {
            "mode": "development",
            "active": true,
            "remaining_seconds": 604800,
            "calls_remaining": 120960
        },
        "rate_limit_per_minute": 12,
        "min_request_interval_seconds": 5,
        "snapshot": {
            "limit_per_hour": 60,
            "used_last_hour": 3,
            "max_updated_since_age_seconds": 3600
        }
    },
    "meta": {
        "mode": "development",
        "calls_remaining": 120960
    }
}
GET /api/v1/health 호출 1회

데이터 신선도

서버 시각, 마지막 경기/배당/결과 갱신 시각, 수집기 노드 상태를 돌려줍니다. 개발 기간에는 가상 상태를 반환합니다. 호출 1회를 사용합니다.

파라미터형식필수설명
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/health
curl -s "https://sposerv.com/api/v1/health" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/health", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/health");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/health"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/health",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/health");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "server_time_ts": 1790250228,
        "last_odds_at": "2026-09-25 20:11:03",
        "collectors": [
            {
                "node": "PC-1",
                "job_id": "football",
                "phase": "collecting",
                "stale": false
            }
        ]
    }
}
GET /api/v1/sources 호출 1회

수집처 목록

배당을 수집하는 원천 사이트(수집처) 목록입니다. 경기·북메이커·평균 배당은 수집처별로 따로 저장되며 같은 현실의 경기라도 수집처가 다르면 event_id가 다릅니다(bmbets 경기 id는 bm 접두). source 파라미터를 주지 않은 요청은 기본 수집처(oddsportal)만 돌려주므로 기존 연동은 그대로 동작합니다. average_provider_id는 소비 측에서 이 수집처 평균 배당에 붙이는 가상 북메이커 번호(931 OddsPortal, 932 BMBets)입니다. has_results가 false인 수집처는 결과(스코어)를 제공하지 않습니다.

파라미터형식필수설명
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/sources
curl -s "https://sposerv.com/api/v1/sources" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/sources", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/sources");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/sources"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/sources",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/sources");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "default_source": "oddsportal",
        "sources": [
            {
                "source_id": "oddsportal",
                "name": "OddsPortal",
                "site_url": "https://www.oddsportal.com/",
                "event_prefix": "",
                "provider_base": 0,
                "average_provider_id": 931,
                "has_results": true,
                "enabled": true,
                "bookmakers": 60,
                "events_7d": 3120,
                "last_odds_ts": 1790250201,
                "is_default": true
            },
            {
                "source_id": "bmbets",
                "name": "BMBets",
                "site_url": "https://www.bmbets.com/",
                "event_prefix": "bm",
                "provider_base": 200000,
                "average_provider_id": 932,
                "has_results": false,
                "enabled": true,
                "bookmakers": 41,
                "events_7d": 880,
                "last_odds_ts": 1790250190,
                "is_default": false
            }
        ]
    }
}
GET /api/v1/sports 호출 1회

종목 목록

최근 7일 안에 경기가 있는 종목과 경기 수(예정/진행 중/앞으로) 요약입니다. source로 수집처를 고를 수 있습니다(기본 oddsportal).

파라미터형식필수설명
sourcestring수집처 id 또는 all. 기본 oddsportal
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/sports
curl -s "https://sposerv.com/api/v1/sports" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/sports", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/sports");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/sports"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/sports",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/sports");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": [
        {
            "sport_key": "football",
            "sport_name": "football",
            "sport_name_ko": "축구",
            "sport_id": 1,
            "events_7d": 1240,
            "scheduled": 310,
            "live": 12,
            "upcoming": 322,
            "last_odds_ts": 1790250201
        }
    ]
}
GET /api/v1/odds 호출 1회

여러 종목 · 기간별 배당

최대 10개 종목을 동일한 최대 24시간 구간으로 조회합니다. snapshot=1(기본)은 기간의 모든 배당을 킥오프 순서로, snapshot=0은 updated_since_ts 이후 바뀐 배당만(내려간 가격 포함, active=false) 돌려줍니다. 한 페이지당 호출 1회이며 next_page를 순서대로 5초 간격으로 요청하세요. 스냅샷 시작(page=1)은 계정당 시간당 한도가 있고, 이어지는 페이지와 변경분 조회는 한도에 포함되지 않습니다. 북메이커를 지정해 필요한 배당사만 받을 수 있습니다. source로 수집처를 고르며(기본 oddsportal, all이면 전체) 각 행의 source_id로 어느 수집처의 배당인지 알 수 있습니다. 응답은 2MiB 이내이며 초과 시 limit을 줄이세요.

파라미터형식필수설명
sportsstring예쉼표 구분 종목 (football,basketball)
sourcestring수집처 id(oddsportal, bmbets) 또는 all. 기본 oddsportal. 페이지를 이어 받을 때 같은 값을 보내세요
from_tsint구간 시작 unix 초
to_tsint구간 끝 unix 초, 최대 24시간
snapshot0|11(기본): 기간 전체. 0: updated_since_ts 이후 바뀐 것만. updated_since_ts를 주면 0으로 간주
limitint기본 200, 최대 500 가격 행
pageint1부터 순서대로. next_page 사용 (최대 10000)
provider_idint북메이커 하나
provider_idsstring북메이커 id 여러 개 (쉼표, 최대 50개). 예: 417,16
bookmakersstring북메이커 slug 여러 개 (쉼표). /reference/bookmakers의 slug. 예: bet365,1xbet. source=all이면 같은 slug의 모든 수집처 북메이커를 포함
betting_type_idint마켓
scope_idint경기 구간
active_only0|1스냅샷 기본 1, 변경분 기본 0(내려간 가격도 전달)
updated_since_tsint최근 3600초 안의 변경분 기준 시각. 이전 조회가 sync_complete=true일 때의 checkpoint_ts 사용. 기준 초 포함
updated_sincestringupdated_since_ts 대신 KST YYYY-MM-DD HH:MM:SS 또는 RFC3339 (예: 2026-10-06T09:00:00+09:00). URL 인코딩 필수
updated_until_tsint변경분 종료 시각(unix 초, 포함). 기본 첫 페이지 요청 시각, 현재보다 미래 불가
updated_untilstringupdated_until_ts 대신 KST 또는 RFC3339. 시작/종료 모두 같은 형식 규칙
all_dates0|1변경분 전용. 1이면 경기 날짜와 무관하게 변경된 행 조회. date/from_ts/to_ts와 함께 사용 불가
query_idstringpage=2부터 첫 응답의 query_id(32자리)를 같은 필터와 함께 전달. 병렬 조회 구분
event_idsstring쉼표로 구분한 event_id, 최대 100개
tournament_idsstring쉼표로 구분한 리그 ID, 최대 50개. tournament_id와 합침
tournament_idint리그 하나
countrystring원문 국가 이름 일치 (예: England)
statestring쉼표로 구분한 경기 수집 상태. scheduled,live,finished 등 최대 10개
prioritystringhigh | normal | low
qstring국가·리그·홈·원정 이름 검색, 최대 60자. 라이브는 한글명도 검색
has_odds0|11이면 배당이 수집된 경기만
dateYYYY-MM-DDKST 경기 날짜. from_ts/to_ts와 함께 사용 불가
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/odds?sports=football,basketball&date=2026-11-11&limit=200
curl -s "https://sposerv.com/api/v1/odds?sports=football,basketball&date=2026-11-11&limit=200" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/odds?sports=football,basketball&date=2026-11-11&limit=200", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/odds?sports=football,basketball&date=2026-11-11&limit=200");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/odds?sports=football,basketball&date=2026-11-11&limit=200"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/odds?sports=football,basketball&date=2026-11-11&limit=200",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/odds?sports=football,basketball&date=2026-11-11&limit=200");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "sports": [
            "football",
            "basketball"
        ],
        "from_ts": 1790694000,
        "to_ts": 1790780399,
        "snapshot": true,
        "updated_since_ts": null,
        "next_updated_since_ts": 1790750970,
        "page": 1,
        "limit": 200,
        "has_more": true,
        "next_page": 2,
        "narrow_range_required": false,
        "odds": [
            {
                "event_id": "dxIvPyIk",
                "sport_key": "football",
                "sport_name_ko": "축구",
                "start_ts": 1790754800,
                "home_name": "Namibia",
                "home_name_ko": "나미비아",
                "away_name": "Congo",
                "away_name_ko": "콩고 공화국",
                "tournament_name": "Africa Cup of Nations",
                "tournament_name_ko": "아프리카 네이션스컵",
                "betting_type_id": 1,
                "scope_id": 2,
                "handicap_type_id": 0,
                "handicap_value": 0,
                "mixed_parameter_id": 0,
                "provider_id": 16,
                "bookmaker": "bet365",
                "bookmaker_ko": "벳365",
                "outcome_labels": [
                    "1",
                    "X",
                    "2"
                ],
                "outcome_labels_ko": [
                    "홈 승",
                    "무승부",
                    "원정 승"
                ],
                "odds": [
                    2.4,
                    3.1,
                    3
                ],
                "opening": [
                    2.3,
                    3.25,
                    3.4
                ],
                "active": true,
                "fetched_at": "2026-09-30 15:20:10",
                "changed_at": "2026-09-30 15:07:16"
            }
        ],
        "query_id": "0123456789abcdef0123456789abcdef",
        "all_dates": false,
        "updated_until_ts": 1790751000,
        "sync_complete": false,
        "checkpoint_ts": null
    }
}
GET /api/v1/events 호출 1회

경기 목록

킥오프 시각 구간으로 경기를 조회합니다. 기본 구간은 지금부터 6시간 전 ~ 18시간 후입니다. snapshot=1(기본)은 구간의 모든 경기, snapshot=0은 updated_since_ts 이후 이름·일정·상태·경기장·결과가 바뀐 경기만 돌려줍니다. 결과가 있으면 result 요약(종료 방식 finish_type, 연장 진행 여부 overtime, 정규시간·연장 포함 스코어 scores)이 함께 옵니다. 종목·국가·리그·라운드·팀·경기장 이름에는 한글명(*_ko)이 함께 옵니다. total은 조회를 시작한(page=1) 시점의 전체 건수이며 이어지는 페이지에서도 같은 값입니다. source로 수집처를 고르며(기본 oddsportal) 각 경기의 source_id·native_event_id(원천 사이트의 id)가 함께 옵니다.

파라미터형식필수설명
sportsstring예쉼표로 종목 지정, 최대 10개 (football,basketball). sport 단일 값도 지원
sourcestring수집처 id(oddsportal, bmbets) 또는 all. 기본 oddsportal. 페이지를 이어 받을 때 같은 값을 보내세요
from_tsint시작 구간 (unix 초). to_ts와 함께 최대 24시간
to_tsint끝 구간 (unix 초)
snapshot0|11(기본): 기간 전체. 0: updated_since_ts 이후 바뀐 것만. updated_since_ts를 주면 0으로 간주
pageint1부터 순서대로. next_page 사용
limitint기본 50, 최대 100
updated_since_tsint최근 3600초 안의 변경분 기준 시각. 이전 조회가 sync_complete=true일 때의 checkpoint_ts 사용. 기준 초 포함
updated_sincestringupdated_since_ts 대신 KST YYYY-MM-DD HH:MM:SS 또는 RFC3339 (예: 2026-10-06T09:00:00+09:00). URL 인코딩 필수
updated_until_tsint변경분 종료 시각(unix 초, 포함). 기본 첫 페이지 요청 시각, 현재보다 미래 불가
updated_untilstringupdated_until_ts 대신 KST 또는 RFC3339. 시작/종료 모두 같은 형식 규칙
all_dates0|1변경분 전용. 1이면 경기 날짜와 무관하게 변경된 행 조회. date/from_ts/to_ts와 함께 사용 불가
query_idstringpage=2부터 첫 응답의 query_id(32자리)를 같은 필터와 함께 전달. 병렬 조회 구분
event_idsstring쉼표로 구분한 event_id, 최대 100개
tournament_idsstring쉼표로 구분한 리그 ID, 최대 50개. tournament_id와 합침
tournament_idint리그 하나
countrystring원문 국가 이름 일치 (예: England)
statestring쉼표로 구분한 경기 수집 상태. scheduled,live,finished 등 최대 10개
prioritystringhigh | normal | low
qstring국가·리그·홈·원정 이름 검색, 최대 60자. 라이브는 한글명도 검색
has_odds0|11이면 배당이 수집된 경기만
dateYYYY-MM-DDKST 경기 날짜. from_ts/to_ts와 함께 사용 불가
include_total0|1기본 1. 0이면 COUNT를 생략하고 total=null 반환
include_result0|1기본 1. 0이면 결과 조인과 각 경기의 result 필드를 생략
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events?sport=football&date=2026-11-11&limit=20
curl -s "https://sposerv.com/api/v1/events?sport=football&date=2026-11-11&limit=20" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events?sport=football&date=2026-11-11&limit=20", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events?sport=football&date=2026-11-11&limit=20");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events?sport=football&date=2026-11-11&limit=20"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events?sport=football&date=2026-11-11&limit=20",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events?sport=football&date=2026-11-11&limit=20");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "snapshot": true,
        "updated_since_ts": null,
        "next_updated_since_ts": 1790750970,
        "page": 1,
        "limit": 20,
        "has_more": true,
        "next_page": 2,
        "total": 312,
        "events": [
            {
                "event_id": "dxIvPyIk",
                "sport_key": "football",
                "sport_name": "football",
                "sport_name_ko": "축구",
                "country_name": "Africa",
                "country_name_ko": "아프리카",
                "tournament_name": "Africa Cup of Nations",
                "tournament_name_ko": "아프리카 네이션스컵",
                "home_name": "Namibia",
                "home_name_ko": "나미비아",
                "away_name": "Congo",
                "away_name_ko": "콩고 공화국",
                "venue": null,
                "venue_ko": null,
                "start_ts": 1790254800,
                "start_at": "2026-09-24 22:00:00",
                "collect_state": "finished",
                "priority": "high",
                "changed_at": "2026-09-25 00:01:12",
                "result": {
                    "event_status": "finished",
                    "finish_type": "regular",
                    "is_final": true,
                    "home_score": 1,
                    "away_score": 0,
                    "result_text": "1:0",
                    "winner": "home",
                    "overtime": false,
                    "scores": {
                        "regular_time": {
                            "scope_id": 2,
                            "period": "Full Time",
                            "home": 1,
                            "away": 0,
                            "period_ko": "정규시간"
                        },
                        "including_overtime": {
                            "scope_id": 1,
                            "period": "FT including OT",
                            "home": 1,
                            "away": 0,
                            "period_ko": "연장 포함 전체 경기"
                        }
                    }
                }
            }
        ],
        "query_id": "0123456789abcdef0123456789abcdef",
        "all_dates": false,
        "updated_until_ts": 1790751000,
        "sync_complete": false,
        "checkpoint_ts": null,
        "narrow_range_required": false
    }
}
GET /api/v1/events/{event_id} 호출 1회

경기 상세

경기 정보와 결과 요약, 저장된 마켓(배당 종류×구간) 목록과 각 마켓의 마지막 확인/변경 시각을 돌려줍니다.

파라미터형식필수설명
event_idstring예경기 id (경로)
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events/bmZB0IUp
curl -s "https://sposerv.com/api/v1/events/bmZB0IUp" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events/bmZB0IUp", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events/bmZB0IUp");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events/bmZB0IUp"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events/bmZB0IUp",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events/bmZB0IUp");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "event_id": "dxIvPyIk",
        "home_name": "Namibia",
        "home_name_ko": "나미비아",
        "away_name": "Congo",
        "away_name_ko": "콩고 공화국",
        "start_ts": 1790254800,
        "markets": [
            {
                "betting_type_id": 1,
                "market": "1X2",
                "market_ko": "승무패",
                "scope_id": 2,
                "period": "Full Time",
                "period_ko": "정규시간",
                "provider_count": 14,
                "fetched_at": "2026-09-24 21:55:10",
                "last_changed_at": "2026-09-24 21:40:02"
            }
        ]
    }
}
GET /api/v1/events/{event_id}/markets 호출 1회

마켓 신선도

경기의 마켓별 마지막 확인 시각(fetched_at)과 마지막 변경 시각(last_changed_at)만 가볍게 조회합니다. "배당이 안 바뀐 것"과 "확인이 안 된 것"을 구분할 때 씁니다.

파라미터형식필수설명
event_idstring예경기 id (경로)
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events/bmZB0IUp/markets
curl -s "https://sposerv.com/api/v1/events/bmZB0IUp/markets" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events/bmZB0IUp/markets", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events/bmZB0IUp/markets");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events/bmZB0IUp/markets"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events/bmZB0IUp/markets",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events/bmZB0IUp/markets");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "event_id": "dxIvPyIk",
        "markets": [
            {
                "betting_type_id": 2,
                "market": "O/U",
                "market_ko": "오버/언더",
                "scope_id": 2,
                "period": "Full Time",
                "period_ko": "정규시간",
                "line_count": 7,
                "fetched_at": "2026-09-24 21:55:10",
                "last_changed_at": "2026-09-24 21:12:44"
            }
        ]
    }
}
GET /api/v1/events/{event_id}/odds 호출 1회

현재 배당

경기의 현재 배당을 마켓 → 라인(기준점) → 북메이커 가격 순으로 묶어 돌려줍니다. provider_ids나 bookmakers로 받을 배당사를 고를 수 있습니다(평균은 선택과 무관하게 전체 활성 북메이커 기준). odds[i]는 outcome_labels[i]에 대응하며 outcome_labels_ko[i]가 같은 자리의 한글 표기입니다. 각 라인의 average는 거래소를 제외한 활성 가격의 평균입니다.

파라미터형식필수설명
event_idstring예경기 id (경로)
betting_type_idint마켓 id (1=1X2, 2=O/U, 5=AH ...)
scope_idint구간 id (2=Full Time, 3=1st Half ...)
provider_idint북메이커 id
provider_idsstring북메이커 id 여러 개 (쉼표, 최대 50개). 예: 417,16
bookmakersstring북메이커 slug 여러 개 (쉼표). /reference/bookmakers의 slug. 예: bet365,1xbet. slug는 수집처 안에서만 유일하므로 경기의 수집처 slug를 쓰세요
active_only0|1기본 1. 0이면 북메이커가 내린 가격(active=false)도 포함
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events/bmZB0IUp/odds?betting_type_id=1&scope_id=2
curl -s "https://sposerv.com/api/v1/events/bmZB0IUp/odds?betting_type_id=1&scope_id=2" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events/bmZB0IUp/odds?betting_type_id=1&scope_id=2", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events/bmZB0IUp/odds?betting_type_id=1&scope_id=2");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events/bmZB0IUp/odds?betting_type_id=1&scope_id=2"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events/bmZB0IUp/odds?betting_type_id=1&scope_id=2",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events/bmZB0IUp/odds?betting_type_id=1&scope_id=2");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "event_id": "dxIvPyIk",
        "markets": [
            {
                "betting_type_id": 1,
                "market": "1X2",
                "market_ko": "승무패",
                "outcome_labels": [
                    "1",
                    "X",
                    "2"
                ],
                "outcome_labels_ko": [
                    "홈 승",
                    "무승부",
                    "원정 승"
                ],
                "scope_id": 2,
                "period": "Full Time",
                "period_ko": "정규시간",
                "fetched_at": "2026-09-24 21:55:10",
                "lines": [
                    {
                        "handicap_type_id": 0,
                        "handicap_value": 0,
                        "mixed_parameter_id": 0,
                        "mixed_parameter_name": null,
                        "mixed_parameter_name_ko": null,
                        "prices": [
                            {
                                "provider_id": 417,
                                "bookmaker": "1xBet",
                                "bookmaker_ko": "원엑스벳",
                                "odds": [
                                    2.36,
                                    3.04,
                                    3.07
                                ],
                                "opening": [
                                    2.24,
                                    3.2,
                                    3.49
                                ],
                                "active": true,
                                "change_ts": 1790242320
                            }
                        ],
                        "average": {
                            "odds": [
                                2.41,
                                3.12,
                                3.05
                            ],
                            "provider_count": 13
                        }
                    }
                ]
            }
        ]
    }
}
GET /api/v1/events/{event_id}/odds/history 호출 1회

배당 변동 이력

한 마켓(배당 종류×구간)의 배당 변경 이력을 최신순으로 돌려줍니다. 북메이커별로 좁힐 수 있습니다.

파라미터형식필수설명
event_idstring예경기 id (경로)
betting_type_idint예마켓 id
scope_idint예구간 id
provider_idint북메이커 id
provider_idsstring북메이커 id 여러 개 (쉼표, 최대 50개). 예: 417,16
bookmakersstring북메이커 slug 여러 개 (쉼표). /reference/bookmakers의 slug. 예: bet365,1xbet
since_tsint이 시각(unix 초) 이후 이력만
limitint기본 200, 최대 1000
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events/bmZB0IUp/odds/history?betting_type_id=1&scope_id=2&limit=100
curl -s "https://sposerv.com/api/v1/events/bmZB0IUp/odds/history?betting_type_id=1&scope_id=2&limit=100" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events/bmZB0IUp/odds/history?betting_type_id=1&scope_id=2&limit=100", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events/bmZB0IUp/odds/history?betting_type_id=1&scope_id=2&limit=100");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events/bmZB0IUp/odds/history?betting_type_id=1&scope_id=2&limit=100"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events/bmZB0IUp/odds/history?betting_type_id=1&scope_id=2&limit=100",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events/bmZB0IUp/odds/history?betting_type_id=1&scope_id=2&limit=100");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "event_id": "dxIvPyIk",
        "betting_type_id": 1,
        "scope_id": 2,
        "history": [
            {
                "provider_id": 417,
                "bookmaker": "1xBet",
                "bookmaker_ko": "원엑스벳",
                "handicap_value": 0,
                "odds": [
                    2.36,
                    3.04,
                    3.07
                ],
                "active": true,
                "fetched_ts": 1790250232,
                "captured_at": "2026-09-24 20:43:52"
            }
        ]
    }
}
GET /api/v1/events/{event_id}/odds/average 호출 1회

평균 배당

경기의 마켓·라인별 평균 배당입니다. 활성 가격만, 거래소(Betfair Exchange 등)는 제외하고 계산하며 배당이 저장될 때마다 다시 계산됩니다. 평균은 그 경기를 수집한 수집처의 북메이커만으로 계산합니다(수집처 간 합산 없음). 응답의 source_id와 average_provider_id(931 OddsPortal, 932 BMBets)로 어느 수집처 평균인지 구분하세요. 사이트 표시값과 대조할 때는 목록 피드의 avgOdds가 아니라 이 값을 기준으로 삼으세요. odds 엔드포인트의 각 라인에도 같은 값이 average로 포함됩니다.

파라미터형식필수설명
event_idstring예경기 id (경로)
betting_type_idint마켓 id
scope_idint구간 id
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events/bmZB0IUp/odds/average?betting_type_id=1&scope_id=2
curl -s "https://sposerv.com/api/v1/events/bmZB0IUp/odds/average?betting_type_id=1&scope_id=2" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average?betting_type_id=1&scope_id=2", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average?betting_type_id=1&scope_id=2");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average?betting_type_id=1&scope_id=2"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average?betting_type_id=1&scope_id=2",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average?betting_type_id=1&scope_id=2");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "event_id": "dxIvPyIk",
        "source_id": "oddsportal",
        "average_provider_id": 931,
        "markets": [
            {
                "betting_type_id": 1,
                "market": "1X2",
                "market_ko": "승무패",
                "outcome_labels": [
                    "1",
                    "X",
                    "2"
                ],
                "outcome_labels_ko": [
                    "홈 승",
                    "무승부",
                    "원정 승"
                ],
                "scope_id": 2,
                "period": "Full Time",
                "period_ko": "정규시간",
                "lines": [
                    {
                        "handicap_value": 0,
                        "mixed_parameter_id": 0,
                        "average": {
                            "odds": [
                                2.41,
                                3.12,
                                3.05
                            ],
                            "provider_count": 13,
                            "changed_at": "2026-09-24 21:40:02"
                        }
                    }
                ]
            }
        ]
    }
}
GET /api/v1/events/{event_id}/odds/average/history 호출 1회

평균 배당 이력

한 마켓의 평균 배당이 바뀐 기록을 최신순으로 돌려줍니다. provider_count가 0이면 그 라인의 가격이 모두 내려간 시점입니다.

파라미터형식필수설명
event_idstring예경기 id (경로)
betting_type_idint예마켓 id
scope_idint예구간 id
since_tsint이 시각(unix 초) 이후만
limitint기본 200, 최대 1000
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events/bmZB0IUp/odds/average/history?betting_type_id=1&scope_id=2
curl -s "https://sposerv.com/api/v1/events/bmZB0IUp/odds/average/history?betting_type_id=1&scope_id=2" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average/history?betting_type_id=1&scope_id=2", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average/history?betting_type_id=1&scope_id=2");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average/history?betting_type_id=1&scope_id=2"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average/history?betting_type_id=1&scope_id=2",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events/bmZB0IUp/odds/average/history?betting_type_id=1&scope_id=2");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "event_id": "dxIvPyIk",
        "history": [
            {
                "handicap_value": 0,
                "odds": [
                    2.41,
                    3.12,
                    3.05
                ],
                "provider_count": 13,
                "fetched_ts": 1790250232,
                "captured_at": "2026-09-24 20:43:52"
            }
        ]
    }
}
GET /api/v1/events/{event_id}/result 호출 1회

경기 결과

라이브 스코어 또는 최종 결과입니다. home_score/away_score는 연장·승부차기를 포함한 최종 스코어(승부차기 승자 +1), regular_time은 정규시간 스코어, periods는 구간별 스코어입니다. overtime은 정규시간 이후 연장(연장전·OT·연장 이닝·승부차기/슛아웃)으로 이어졌는지(true/false, 아직 모르면 null)입니다. scores는 정산용 스코어를 배당의 scope_id와 함께 줍니다: regular_time = 정규시간(scope 2), including_overtime = 연장 포함(scope 1). 경기가 끝나지 않았거나 기권·부전승·몰수, 승자로만 판정하는 종목(복싱·종합격투기·크리켓)은 null이며 이때는 스코어로 자동 정산하지 마세요.

파라미터형식필수설명
event_idstring예경기 id (경로)
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/events/bmZB0IUp/result
curl -s "https://sposerv.com/api/v1/events/bmZB0IUp/result" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/events/bmZB0IUp/result", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/events/bmZB0IUp/result");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/events/bmZB0IUp/result"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/events/bmZB0IUp/result",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/events/bmZB0IUp/result");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "event_id": "Y1q1vVn1",
        "home_name": "Morocco",
        "home_name_ko": "모로코",
        "away_name": "Mali",
        "away_name_ko": "말리",
        "result": {
            "event_status": "finished",
            "finish_type": "penalties",
            "is_final": true,
            "event_stage_name": "After Penalties",
            "event_stage_name_ko": "승부차기 후 종료",
            "home_score": 5,
            "away_score": 4,
            "regular_time": {
                "home": 2,
                "away": 2
            },
            "overtime": true,
            "scores": {
                "regular_time": {
                    "scope_id": 2,
                    "period": "Full Time",
                    "home": 2,
                    "away": 2,
                    "period_ko": "정규시간"
                },
                "including_overtime": {
                    "scope_id": 1,
                    "period": "FT including OT",
                    "home": 5,
                    "away": 4,
                    "period_ko": "연장 포함 전체 경기"
                }
            },
            "periods": [
                {
                    "home": 1,
                    "away": 2
                },
                {
                    "home": 1,
                    "away": 0
                },
                {
                    "home": 2,
                    "away": 2
                },
                {
                    "home": 4,
                    "away": 3
                }
            ],
            "result_text": "5:4 pen.",
            "winner": "home"
        }
    }
}
GET /api/v1/results 호출 1회

결과 목록

킥오프 구간의 결과(라이브 포함)를 목록으로 돌려줍니다. final_only=1이면 최종 결과만. snapshot=0과 updated_since_ts로 그 이후 스코어·상태가 바뀐 결과만 받을 수 있습니다. 결과를 제공하지 않는 수집처(bmbets)의 경기는 포함되지 않습니다.

파라미터형식필수설명
sportsstring예쉼표 구분 최대 10종목, 단일 sport도 지원
sourcestring수집처 id 또는 all. 기본 oddsportal
from_tsint킥오프 구간 시작 unix 초 (최대 24시간)
to_tsint킥오프 구간 끝 unix 초
final_only0|11이면 is_final=true만
statusstringlive | finished | postponed | cancelled ...
snapshot0|11(기본): 기간 전체. 0: updated_since_ts 이후 바뀐 것만. updated_since_ts를 주면 0으로 간주
pageint1부터 순서대로. next_page 사용
limitint기본 50, 최대 100
updated_since_tsint최근 3600초 안의 변경분 기준 시각. 이전 조회가 sync_complete=true일 때의 checkpoint_ts 사용. 기준 초 포함
updated_sincestringupdated_since_ts 대신 KST YYYY-MM-DD HH:MM:SS 또는 RFC3339 (예: 2026-10-06T09:00:00+09:00). URL 인코딩 필수
updated_until_tsint변경분 종료 시각(unix 초, 포함). 기본 첫 페이지 요청 시각, 현재보다 미래 불가
updated_untilstringupdated_until_ts 대신 KST 또는 RFC3339. 시작/종료 모두 같은 형식 규칙
all_dates0|1변경분 전용. 1이면 경기 날짜와 무관하게 변경된 행 조회. date/from_ts/to_ts와 함께 사용 불가
query_idstringpage=2부터 첫 응답의 query_id(32자리)를 같은 필터와 함께 전달. 병렬 조회 구분
event_idsstring쉼표로 구분한 event_id, 최대 100개
tournament_idsstring쉼표로 구분한 리그 ID, 최대 50개. tournament_id와 합침
tournament_idint리그 하나
countrystring원문 국가 이름 일치 (예: England)
statestring쉼표로 구분한 경기 수집 상태. scheduled,live,finished 등 최대 10개
prioritystringhigh | normal | low
qstring국가·리그·홈·원정 이름 검색, 최대 60자. 라이브는 한글명도 검색
has_odds0|11이면 배당이 수집된 경기만
dateYYYY-MM-DDKST 경기 날짜. from_ts/to_ts와 함께 사용 불가
include_total0|1기본 1. 0이면 COUNT를 생략하고 total=null 반환
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/results?sport=football&date=2026-11-11&final_only=1
curl -s "https://sposerv.com/api/v1/results?sport=football&date=2026-11-11&final_only=1" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/results?sport=football&date=2026-11-11&final_only=1", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/results?sport=football&date=2026-11-11&final_only=1");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/results?sport=football&date=2026-11-11&final_only=1"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/results?sport=football&date=2026-11-11&final_only=1",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/results?sport=football&date=2026-11-11&final_only=1");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "snapshot": true,
        "next_updated_since_ts": 1790750970,
        "page": 1,
        "limit": 50,
        "has_more": true,
        "next_page": 2,
        "total": 96,
        "results": [
            {
                "event_id": "EeTPslzo",
                "sport_key": "football",
                "sport_name_ko": "축구",
                "tournament_name": "Africa Cup of Nations U20",
                "tournament_name_ko": "아프리카 네이션스컵 U20",
                "home_name": "Uganda U20",
                "home_name_ko": "우간다 U20",
                "away_name": "Burundi U20",
                "away_name_ko": "부룬디 U20",
                "event_status": "finished",
                "finish_type": "regular",
                "is_final": true,
                "home_score": 2,
                "away_score": 0,
                "regular_time": {
                    "home": 2,
                    "away": 0
                },
                "overtime": false,
                "scores": {
                    "regular_time": {
                        "scope_id": 2,
                        "period": "Full Time",
                        "home": 2,
                        "away": 0,
                        "period_ko": "정규시간"
                    },
                    "including_overtime": {
                        "scope_id": 1,
                        "period": "FT including OT",
                        "home": 2,
                        "away": 0,
                        "period_ko": "연장 포함 전체 경기"
                    }
                },
                "winner": "home"
            }
        ],
        "query_id": "0123456789abcdef0123456789abcdef",
        "all_dates": false,
        "updated_until_ts": 1790751000,
        "sync_complete": false,
        "checkpoint_ts": null,
        "narrow_range_required": false
    }
}
GET /api/v1/reference/bookmakers 호출 1회

북메이커 사전

북메이커(provider_id)의 이름과 slug 사전입니다. name_ko로 한글명이 함께 옵니다. 같은 회사라도 수집처가 다르면 provider_id가 다릅니다(bmbets는 200000+원천 id). source_id·native_provider_id(원천 사이트의 id)·brand_key(수집처 간 같은 회사를 묶는 참고 키)·is_exchange(평균에서 제외되는 거래소)가 함께 옵니다. source로 수집처를 고를 수 있습니다(기본 oddsportal). 호출 1회를 사용하며 하루 한 번 정도 받아 캐시하면 충분합니다. 개발 기간에는 개발용 사전을 반환합니다.

파라미터형식필수설명
sourcestring수집처 id 또는 all. 기본 oddsportal
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/reference/bookmakers
curl -s "https://sposerv.com/api/v1/reference/bookmakers" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/reference/bookmakers", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/reference/bookmakers");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/reference/bookmakers"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/reference/bookmakers",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/reference/bookmakers");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": [
        {
            "provider_id": 417,
            "name": "1xBet",
            "name_ko": "원엑스벳",
            "slug": "1xbet",
            "source_id": "oddsportal",
            "native_provider_id": 417,
            "brand_key": "1xbet",
            "is_exchange": false
        }
    ]
}
GET /api/v1/reference/betting-types 호출 1회

마켓 사전

마켓(betting_type_id)의 이름, 약칭과 결과 순서를 돌려줍니다. outcome_labels[i]는 배당 odds[i]와 같은 순서입니다. *_ko는 한글명입니다. 호출 1회를 사용하며 캐시해 사용하세요. 개발 기간에는 개발용 사전을 반환합니다.

파라미터형식필수설명
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/reference/betting-types
curl -s "https://sposerv.com/api/v1/reference/betting-types" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/reference/betting-types", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/reference/betting-types");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/reference/betting-types"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/reference/betting-types",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/reference/betting-types");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": [
        {
            "betting_type_id": 1,
            "name": "1X2",
            "name_ko": "승무패",
            "short_name": "1X2",
            "short_name_ko": "승무패",
            "outcome_labels": [
                "1",
                "X",
                "2"
            ],
            "outcome_labels_ko": [
                "홈 승",
                "무승부",
                "원정 승"
            ]
        }
    ]
}
GET /api/v1/reference/scopes 호출 1회

경기 구간 사전

경기 구간(scope_id)의 이름과 약칭을 돌려줍니다. *_ko는 한글명입니다. 호출 1회를 사용하며 캐시해 사용하세요. 개발 기간에는 개발용 사전을 반환합니다.

파라미터형식필수설명
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/reference/scopes
curl -s "https://sposerv.com/api/v1/reference/scopes" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/reference/scopes", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/reference/scopes");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/reference/scopes"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/reference/scopes",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/reference/scopes");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": [
        {
            "scope_id": 2,
            "name": "Full Time",
            "name_ko": "정규시간",
            "short_name": "FT",
            "short_name_ko": "정규시간"
        }
    ]
}
GET /api/v1/reference/names 호출 1회

한글명 사전

원문 이름과 한글명을 종류별로 한꺼번에 받습니다. 모든 응답에 *_ko가 이미 들어 있으므로 필수는 아니며, 자체 DB에 이름을 미리 적재하거나 번역 수정분을 주기적으로 동기화할 때 씁니다. 미번역은 name_ko가 null입니다. next_after가 null이 될 때까지 after에 넣어 이어 받으세요(페이지마다 호출 1회, 5초 간격). updated_since_ts를 주면 그 시각 이후 추가·수정된 이름만 받습니다. 팀·리그·라운드는 종목별로 구분되고 나머지 종류의 sport는 빈 문자열입니다.

파라미터형식필수설명
entity_typestring예sport | country | tournament | tournament_stage | team | venue | bookmaker | market | period | event_stage | outcome | mixed_parameter
sportstring종목 키 (team, tournament, tournament_stage에서 사용)
updated_since_tsint이 시각(unix 초) 이후 추가되거나 한글명이 바뀐 이름만
limitint기본 200, 최대 500
afterstring이전 응답의 next_after
include_names0|1기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
예시 요청 /api/v1/reference/names?entity_type=team&sport=football&limit=200
curl -s "https://sposerv.com/api/v1/reference/names?entity_type=team&sport=football&limit=200" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Accept: application/json"
// Node.js 18+ (내장 fetch)
const res = await fetch("https://sposerv.com/api/v1/reference/names?entity_type=team&sport=football&limit=200", {
  headers: { "X-API-Key": "YOUR_API_KEY", "Accept": "application/json" }
});
const json = await res.json();
if (!json.ok) throw new Error(json.code + ": " + json.error);
console.log(json.data);
console.log("남은 호출량:", json.meta.calls_remaining);
<?php
$ch = curl_init("https://sposerv.com/api/v1/reference/names?entity_type=team&sport=football&limit=200");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => ["X-API-Key: YOUR_API_KEY", "Accept: application/json"],
]);
$json = json_decode(curl_exec($ch), true);
curl_close($ch);
if (empty($json['ok'])) {
    throw new RuntimeException($json['code'] . ': ' . $json['error']);
}
print_r($json['data']);
// Java 11+ (java.net.http)
import java.net.URI;
import java.net.http.*;

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://sposerv.com/api/v1/reference/names?entity_type=team&sport=football&limit=200"))
    .header("X-API-Key", "YOUR_API_KEY")
    .header("Accept", "application/json")
    .GET()
    .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
System.out.println(response.body());       // {"ok":true,"data":...}
// JSON 파싱은 Jackson / Gson 등 사용
import requests

r = requests.get("https://sposerv.com/api/v1/reference/names?entity_type=team&sport=football&limit=200",
                 headers={"X-API-Key": "YOUR_API_KEY", "Accept": "application/json",
                          "User-Agent": "my-app/1.0"}, timeout=20)
j = r.json()
if not j["ok"]:
    raise RuntimeError(f"{j['code']}: {j['error']}")
print(j["data"])
print("남은 호출량:", j["meta"]["calls_remaining"])
// .NET 6+
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-API-Key", "YOUR_API_KEY");
var body = await http.GetStringAsync("https://sposerv.com/api/v1/reference/names?entity_type=team&sport=football&limit=200");
using var doc = JsonDocument.Parse(body);
if (!doc.RootElement.GetProperty("ok").GetBoolean())
    throw new Exception(doc.RootElement.GetProperty("error").GetString());
Console.WriteLine(doc.RootElement.GetProperty("data"));
응답 예시
{
    "ok": true,
    "data": {
        "entity_type": "team",
        "sport": "football",
        "limit": 200,
        "next_after": "football:0a1f…",
        "names": [
            {
                "id": "09c2…",
                "entity_type": "team",
                "sport": "football",
                "name": "Arsenal W",
                "name_ko": "아스널 W",
                "updated_ts": 1790748436,
                "updated_at": "2026-09-30 15:07:16"
            }
        ]
    }
}

마켓 · 구간 ID

betting_type_id마켓odds[0] / [1] / [2]
11X21 / X / 2
2Over/UnderOver / Under (handicap_value = 기준 점수)
3Home/Away1 / 2
4Double Chance1X / 12 / X2
5Asian Handicap1 / 2 (handicap_value = 홈 기준)
6Draw No Bet1 / 2
7To Qualify1 / 2
8Correct Score배당 1개, mixed_parameter_name = 스코어
9Half Time / Full Time배당 1개, mixed_parameter_name = 조합
10Odd or EvenOdd / Even
12European Handicap1 / X / 2
13Both Teams to ScoreYes / No
scope_id구간
1FT including OT (연장 포함)
2Full Time (정규시간)
3 / 41st Half / 2nd Half
5~71~3 Period
8~111Q~4Q
12~161~5세트
17~251~9이닝

handicap_value: Over/Under는 기준 점수, Asian Handicap은 홈팀 기준 핸디캡. 야구의 scope 3은 1st Half Innings(5이닝)입니다. 정확한 이름은 /reference/*로 받으세요.

사용 팁

  • 스냅샷은 한 번, 이후는 변경분 — 시작할 때 기간별 스냅샷을 끝까지 받고, sync_complete=true일 때의 checkpoint_ts를 다음 조회의 updated_since_ts로 넘기세요. 변경분 조회는 스냅샷 시작 한도를 사용하지 않으며 필요한 변경 행을 받을 수 있습니다.
  • 조회 간격 — 경기 목록은 10분, 관심 경기 배당은 60초, 멀리 예정된 경기는 5~10분을 권장합니다. 실제 수집 지연은 health와 마켓의 fetched_at으로 확인하세요. 동일 경기의 현재 배당 응답에 평균 배당도 포함되어 별도 평균 조회를 생략할 수 있습니다.
  • 기본 한도 예시 — 라이브 7일 500,000회, 라이브 30일 2,200,000회, 개발 7일 120,960회입니다. 여러 종목을 묶어도 페이지마다 호출 1회입니다.
  • 정산 — 결과의 scores.regular_time(정규시간, scope 2)과 scores.including_overtime(연장 포함, scope 1)을 배당의 scope_id에 맞춰 쓰세요. 각각 regular_time, home_score/away_score와 같은 값이며 승부차기 경기는 승자에 1이 더해진 스코어입니다. overtime은 연장으로 이어졌는지 알려 주고, scores가 null이면 스코어로 자동 정산하지 마세요. 종목·마켓·구간별 기준과 연기·기권 처리는 종목별 결과처리 기준에 있습니다.
  • 평균 배당 — 사이트 표시값과 대조할 때는 /odds/average(거래소 제외, 활성 가격만)를 기준으로 삼으세요.
  • 신선도 — fetched_at은 수집기가 사이트에서 마지막으로 확인한 때, changed_at은 값이 마지막으로 바뀐 때입니다. 둘을 함께 보면 "안 바뀐 것"과 "확인 안 된 것"을 구분할 수 있습니다.
  • 이름 사전 — 북메이커 이름은 /reference/bookmakers로 하루 한 번 받아 캐시하세요. 사전에 없는 북메이커는 #417처럼 표시됩니다.
  • User-Agent — python-requests, Python-urllib 같은 라이브러리 기본 User-Agent는 서버 앞단에서 연결이 끊길 수 있습니다. 자체 이름(예: my-app/1.0)을 지정하세요.
  • 한글명 — 화면에는 *_ko를 쓰고 null이면 원문을 쓰세요. 이름을 자체 DB에 적재한다면 /reference/names를 updated_since_ts와 함께 하루 한 번 받아 수정분을 반영하세요.
텔레그램 문의