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/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회 사용합니다. 오류는 사용량에 포함하지 않습니다. 한도 소진 시 조기 자동 구매나 초과 요금은 없습니다.
계정 전체 API 요청은 최소 5초 간격입니다. 범위 조회는 최대 10개 종목, 24시간이며 경기·결과는 최대 100개, 배당은 500개 가격 행입니다. 응답 상한은 2 MiB입니다. 다음 페이지는 5초 후 요청하세요.
429를 받으면 Retry-After 헤더의 초만큼 기다린 뒤 다시 요청하세요. 거절된 요청도 분당 요청 수에 포함되므로 기다리지 않고 재시도하면 계속 거절됩니다. 한 계정이 1분에 30회를 넘게 보내면 그 분의 나머지 요청은 모두 429이고, 이런 요청이 이어지면 보낸 IP가 5분간 차단됩니다.
기간 전체를 받는 스냅샷 시작은 계정당 시간당 60회입니다. 한 번 받은 뒤에는 snapshot=0&updated_since_ts=…로 변경분만 받으세요.
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_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
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"));
배당을 수집하는 원천 사이트(수집처) 목록입니다. 경기·북메이커·평균 배당은 수집처별로 따로 저장되며 같은 현실의 경기라도 수집처가 다르면 event_id가 다릅니다(bmbets 경기 id는 bm 접두). source 파라미터를 주지 않은 요청은 기본 수집처(oddsportal)만 돌려주므로 기존 연동은 그대로 동작합니다. average_provider_id는 소비 측에서 이 수집처 평균 배당에 붙이는 가상 북메이커 번호(931 OddsPortal, 932 BMBets)입니다. has_results가 false인 수집처는 결과(스코어)를 제공하지 않습니다.
파라미터
형식
필수
설명
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
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"));
최대 10개 종목을 동일한 최대 24시간 구간으로 조회합니다. snapshot=1(기본)은 기간의 모든 배당을 킥오프 순서로, snapshot=0은 updated_since_ts 이후 바뀐 배당만(내려간 가격 포함, active=false) 돌려줍니다. 한 페이지당 호출 1회이며 next_page를 순서대로 5초 간격으로 요청하세요. 스냅샷 시작(page=1)은 계정당 시간당 한도가 있고, 이어지는 페이지와 변경분 조회는 한도에 포함되지 않습니다. 북메이커를 지정해 필요한 배당사만 받을 수 있습니다. source로 수집처를 고르며(기본 oddsportal, all이면 전체) 각 행의 source_id로 어느 수집처의 배당인지 알 수 있습니다. 응답은 2MiB 이내이며 초과 시 limit을 줄이세요.
파라미터
형식
필수
설명
sports
string
예
쉼표 구분 종목 (football,basketball)
source
string
수집처 id(oddsportal, bmbets) 또는 all. 기본 oddsportal. 페이지를 이어 받을 때 같은 값을 보내세요
from_ts
int
구간 시작 unix 초
to_ts
int
구간 끝 unix 초, 최대 24시간
snapshot
0|1
1(기본): 기간 전체. 0: updated_since_ts 이후 바뀐 것만. updated_since_ts를 주면 0으로 간주
limit
int
기본 200, 최대 500 가격 행
page
int
1부터 순서대로. next_page 사용 (최대 10000)
provider_id
int
북메이커 하나
provider_ids
string
북메이커 id 여러 개 (쉼표, 최대 50개). 예: 417,16
bookmakers
string
북메이커 slug 여러 개 (쉼표). /reference/bookmakers의 slug. 예: bet365,1xbet. source=all이면 같은 slug의 모든 수집처 북메이커를 포함
betting_type_id
int
마켓
scope_id
int
경기 구간
active_only
0|1
스냅샷 기본 1, 변경분 기본 0(내려간 가격도 전달)
updated_since_ts
int
최근 3600초 안의 변경분 기준 시각. 이전 조회가 sync_complete=true일 때의 checkpoint_ts 사용. 기준 초 포함
updated_since
string
updated_since_ts 대신 KST YYYY-MM-DD HH:MM:SS 또는 RFC3339 (예: 2026-10-06T09:00:00+09:00). URL 인코딩 필수
updated_until_ts
int
변경분 종료 시각(unix 초, 포함). 기본 첫 페이지 요청 시각, 현재보다 미래 불가
updated_until
string
updated_until_ts 대신 KST 또는 RFC3339. 시작/종료 모두 같은 형식 규칙
all_dates
0|1
변경분 전용. 1이면 경기 날짜와 무관하게 변경된 행 조회. date/from_ts/to_ts와 함께 사용 불가
query_id
string
page=2부터 첫 응답의 query_id(32자리)를 같은 필터와 함께 전달. 병렬 조회 구분
event_ids
string
쉼표로 구분한 event_id, 최대 100개
tournament_ids
string
쉼표로 구분한 리그 ID, 최대 50개. tournament_id와 합침
tournament_id
int
리그 하나
country
string
원문 국가 이름 일치 (예: England)
state
string
쉼표로 구분한 경기 수집 상태. scheduled,live,finished 등 최대 10개
priority
string
high | normal | low
q
string
국가·리그·홈·원정 이름 검색, 최대 60자. 라이브는 한글명도 검색
has_odds
0|1
1이면 배당이 수집된 경기만
date
YYYY-MM-DD
KST 경기 날짜. from_ts/to_ts와 함께 사용 불가
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
킥오프 시각 구간으로 경기를 조회합니다. 기본 구간은 지금부터 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)가 함께 옵니다.
파라미터
형식
필수
설명
sports
string
예
쉼표로 종목 지정, 최대 10개 (football,basketball). sport 단일 값도 지원
source
string
수집처 id(oddsportal, bmbets) 또는 all. 기본 oddsportal. 페이지를 이어 받을 때 같은 값을 보내세요
from_ts
int
시작 구간 (unix 초). to_ts와 함께 최대 24시간
to_ts
int
끝 구간 (unix 초)
snapshot
0|1
1(기본): 기간 전체. 0: updated_since_ts 이후 바뀐 것만. updated_since_ts를 주면 0으로 간주
page
int
1부터 순서대로. next_page 사용
limit
int
기본 50, 최대 100
updated_since_ts
int
최근 3600초 안의 변경분 기준 시각. 이전 조회가 sync_complete=true일 때의 checkpoint_ts 사용. 기준 초 포함
updated_since
string
updated_since_ts 대신 KST YYYY-MM-DD HH:MM:SS 또는 RFC3339 (예: 2026-10-06T09:00:00+09:00). URL 인코딩 필수
updated_until_ts
int
변경분 종료 시각(unix 초, 포함). 기본 첫 페이지 요청 시각, 현재보다 미래 불가
updated_until
string
updated_until_ts 대신 KST 또는 RFC3339. 시작/종료 모두 같은 형식 규칙
all_dates
0|1
변경분 전용. 1이면 경기 날짜와 무관하게 변경된 행 조회. date/from_ts/to_ts와 함께 사용 불가
query_id
string
page=2부터 첫 응답의 query_id(32자리)를 같은 필터와 함께 전달. 병렬 조회 구분
event_ids
string
쉼표로 구분한 event_id, 최대 100개
tournament_ids
string
쉼표로 구분한 리그 ID, 최대 50개. tournament_id와 합침
tournament_id
int
리그 하나
country
string
원문 국가 이름 일치 (예: England)
state
string
쉼표로 구분한 경기 수집 상태. scheduled,live,finished 등 최대 10개
priority
string
high | normal | low
q
string
국가·리그·홈·원정 이름 검색, 최대 60자. 라이브는 한글명도 검색
has_odds
0|1
1이면 배당이 수집된 경기만
date
YYYY-MM-DD
KST 경기 날짜. from_ts/to_ts와 함께 사용 불가
include_total
0|1
기본 1. 0이면 COUNT를 생략하고 total=null 반환
include_result
0|1
기본 1. 0이면 결과 조인과 각 경기의 result 필드를 생략
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
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"));
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"));
경기의 현재 배당을 마켓 → 라인(기준점) → 북메이커 가격 순으로 묶어 돌려줍니다. provider_ids나 bookmakers로 받을 배당사를 고를 수 있습니다(평균은 선택과 무관하게 전체 활성 북메이커 기준). odds[i]는 outcome_labels[i]에 대응하며 outcome_labels_ko[i]가 같은 자리의 한글 표기입니다. 각 라인의 average는 거래소를 제외한 활성 가격의 평균입니다.
파라미터
형식
필수
설명
event_id
string
예
경기 id (경로)
betting_type_id
int
마켓 id (1=1X2, 2=O/U, 5=AH ...)
scope_id
int
구간 id (2=Full Time, 3=1st Half ...)
provider_id
int
북메이커 id
provider_ids
string
북메이커 id 여러 개 (쉼표, 최대 50개). 예: 417,16
bookmakers
string
북메이커 slug 여러 개 (쉼표). /reference/bookmakers의 slug. 예: bet365,1xbet. slug는 수집처 안에서만 유일하므로 경기의 수집처 slug를 쓰세요
active_only
0|1
기본 1. 0이면 북메이커가 내린 가격(active=false)도 포함
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
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"));
경기의 마켓·라인별 평균 배당입니다. 활성 가격만, 거래소(Betfair Exchange 등)는 제외하고 계산하며 배당이 저장될 때마다 다시 계산됩니다. 평균은 그 경기를 수집한 수집처의 북메이커만으로 계산합니다(수집처 간 합산 없음). 응답의 source_id와 average_provider_id(931 OddsPortal, 932 BMBets)로 어느 수집처 평균인지 구분하세요. 사이트 표시값과 대조할 때는 목록 피드의 avgOdds가 아니라 이 값을 기준으로 삼으세요. odds 엔드포인트의 각 라인에도 같은 값이 average로 포함됩니다.
파라미터
형식
필수
설명
event_id
string
예
경기 id (경로)
betting_type_id
int
마켓 id
scope_id
int
구간 id
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
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"));
라이브 스코어 또는 최종 결과입니다. 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_id
string
예
경기 id (경로)
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
킥오프 구간의 결과(라이브 포함)를 목록으로 돌려줍니다. final_only=1이면 최종 결과만. snapshot=0과 updated_since_ts로 그 이후 스코어·상태가 바뀐 결과만 받을 수 있습니다. 결과를 제공하지 않는 수집처(bmbets)의 경기는 포함되지 않습니다.
파라미터
형식
필수
설명
sports
string
예
쉼표 구분 최대 10종목, 단일 sport도 지원
source
string
수집처 id 또는 all. 기본 oddsportal
from_ts
int
킥오프 구간 시작 unix 초 (최대 24시간)
to_ts
int
킥오프 구간 끝 unix 초
final_only
0|1
1이면 is_final=true만
status
string
live | finished | postponed | cancelled ...
snapshot
0|1
1(기본): 기간 전체. 0: updated_since_ts 이후 바뀐 것만. updated_since_ts를 주면 0으로 간주
page
int
1부터 순서대로. next_page 사용
limit
int
기본 50, 최대 100
updated_since_ts
int
최근 3600초 안의 변경분 기준 시각. 이전 조회가 sync_complete=true일 때의 checkpoint_ts 사용. 기준 초 포함
updated_since
string
updated_since_ts 대신 KST YYYY-MM-DD HH:MM:SS 또는 RFC3339 (예: 2026-10-06T09:00:00+09:00). URL 인코딩 필수
updated_until_ts
int
변경분 종료 시각(unix 초, 포함). 기본 첫 페이지 요청 시각, 현재보다 미래 불가
updated_until
string
updated_until_ts 대신 KST 또는 RFC3339. 시작/종료 모두 같은 형식 규칙
all_dates
0|1
변경분 전용. 1이면 경기 날짜와 무관하게 변경된 행 조회. date/from_ts/to_ts와 함께 사용 불가
query_id
string
page=2부터 첫 응답의 query_id(32자리)를 같은 필터와 함께 전달. 병렬 조회 구분
event_ids
string
쉼표로 구분한 event_id, 최대 100개
tournament_ids
string
쉼표로 구분한 리그 ID, 최대 50개. tournament_id와 합침
tournament_id
int
리그 하나
country
string
원문 국가 이름 일치 (예: England)
state
string
쉼표로 구분한 경기 수집 상태. scheduled,live,finished 등 최대 10개
priority
string
high | normal | low
q
string
국가·리그·홈·원정 이름 검색, 최대 60자. 라이브는 한글명도 검색
has_odds
0|1
1이면 배당이 수집된 경기만
date
YYYY-MM-DD
KST 경기 날짜. from_ts/to_ts와 함께 사용 불가
include_total
0|1
기본 1. 0이면 COUNT를 생략하고 total=null 반환
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
북메이커(provider_id)의 이름과 slug 사전입니다. name_ko로 한글명이 함께 옵니다. 같은 회사라도 수집처가 다르면 provider_id가 다릅니다(bmbets는 200000+원천 id). source_id·native_provider_id(원천 사이트의 id)·brand_key(수집처 간 같은 회사를 묶는 참고 키)·is_exchange(평균에서 제외되는 거래소)가 함께 옵니다. source로 수집처를 고를 수 있습니다(기본 oddsportal). 호출 1회를 사용하며 하루 한 번 정도 받아 캐시하면 충분합니다. 개발 기간에는 개발용 사전을 반환합니다.
파라미터
형식
필수
설명
source
string
수집처 id 또는 all. 기본 oddsportal
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
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"));
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"));
원문 이름과 한글명을 종류별로 한꺼번에 받습니다. 모든 응답에 *_ko가 이미 들어 있으므로 필수는 아니며, 자체 DB에 이름을 미리 적재하거나 번역 수정분을 주기적으로 동기화할 때 씁니다. 미번역은 name_ko가 null입니다. next_after가 null이 될 때까지 after에 넣어 이어 받으세요(페이지마다 호출 1회, 5초 간격). updated_since_ts를 주면 그 시각 이후 추가·수정된 이름만 받습니다. 팀·리그·라운드는 종목별로 구분되고 나머지 종류의 sport는 빈 문자열입니다.
파라미터
형식
필수
설명
entity_type
string
예
sport | country | tournament | tournament_stage | team | venue | bookmaker | market | period | event_stage | outcome | mixed_parameter
sport
string
종목 키 (team, tournament, tournament_stage에서 사용)
updated_since_ts
int
이 시각(unix 초) 이후 추가되거나 한글명이 바뀐 이름만
limit
int
기본 200, 최대 500
after
string
이전 응답의 next_after
include_names
0|1
기본 1. 0이면 응답의 한글명 보강을 생략. /reference/names의 name_ko는 유지
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"));
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와 함께 하루 한 번 받아 수정분을 반영하세요.