🏠 Nội bộ · Dùng ngay · Không cần setup

Football API Proxy

Proxy nội bộ cho các dự án bóng đá. Chỉ cần gọi URL, không cần đăng ký API key bên thứ ba. Dữ liệu được cache thông minh trên Cloudflare Edge.

Base URL https://football-proxy-internal.manhpd-football.workers.dev

🎯 Dùng ngay

Chỉ cần 1 thông tin duy nhất: Base URL. Gọi API ngay, không cần cài đặt gì thêm.

Proxy nội bộ — sẵn sàng xài

Worker đang chạy 24/7 trên Cloudflare Edge toàn cầu. Không cần deploy, không cần config — chỉ cần gọi URL.

🔗 Base URL
https://football-proxy-internal.manhpd-football.workers.dev

🏗️ Kiến trúc

Cloudflare Worker hoạt động như reverse proxy với cache layer, đứng giữa client app và API-Football.

📱
Client App
iOS · Android · Web
CF Worker
Proxy + Cache
🏟️
API-Football
api-football.com
1

Client gửi request

App gửi request GET trực tiếp đến Worker URL

2

Kiểm tra cache KV

Worker kiểm tra Cloudflare KV xem dữ liệu đã được cache chưa

3

Cache HIT → trả về ngay

Nếu cache còn fresh, trả response ngay lập tức (< 10ms)

4

Cache MISS → gọi API-Football

Nếu cache hết hạn, Worker forward request đến API-Football với API key

5

Lưu cache + trả response

Lưu response vào KV với TTL phù hợp, trả kết quả cho client

📦 Response Envelope

Tất cả response từ API đều sử dụng cùng một cấu trúc wrapper. Dữ liệu thực tế nằm trong trường response.

📄 Response Envelope Structure
{
  "get": "fixtures",
  "parameters": {
    "live": "all"
  },
  "errors": [],
  "results": 10,
  "paging": {
    "current": 1,
    "total": 1
  },
  "response": [ ... ]   ← dữ liệu thực tế
}
📋 Mô tả các trường
FieldTypeMô tả
getstringTên endpoint đã gọi
parametersobjectCác query params đã gửi
errorsarrayDanh sách lỗi (rỗng = OK)
resultsintegerSố kết quả trong response
pagingobjectThông tin phân trang (current, total)
responsearrayDữ liệu thực tế — mảng các object
Fixtures GET TTL: varies
GET /fixtures?live=all

Lấy danh sách trận đấu. Hỗ trợ nhiều filter: trận đang diễn ra (live), theo ngày, theo giải đấu, theo đội, theo ID.

⚙️ Query Parameters
ParamTypeRequiredMô tả
livestringoptional"all" = tất cả trận đang diễn ra
datestringoptionalLọc theo ngày, format YYYY-MM-DD
idintoptionalFixture ID cụ thể
leagueintoptionalLeague ID — lọc theo giải đấu
seasonintoptionalMùa giải (VD: 2024)
teamintoptionalTeam ID — lọc theo đội
nextintoptionalN trận tiếp theo (kết hợp team/league)
lastintoptionalN trận gần nhất (kết hợp team/league)
📄 Response Model — FixtureResponse
JSON Response (mở rộng)
{
  "fixture": {
    "id": 1517580,
    "referee": "John Smith",
    "timezone": "UTC",
    "date": "2026-06-27T08:30:00+00:00",
    "timestamp": 1782549000,
    "periods": {
      "first": 1782549000,
      "second": null
    },
    "venue": {
      "id": 556,
      "name": "Old Trafford",
      "city": "Manchester"
    },
    "status": {
      "long": "First Half",
      "short": "1H",
      "elapsed": 14,
      "extra": null
    }
  },
  "league": {
    "id": 39,
    "name": "Premier League",
    "country": "England",
    "logo": "https://media.api-sports.io/football/leagues/39.png",
    "flag": "https://media.api-sports.io/flags/gb-eng.svg",
    "season": 2024,
    "round": "Regular Season - 21"
  },
  "teams": {
    "home": {
      "id": 33,
      "name": "Manchester United",
      "logo": "https://media.api-sports.io/football/teams/33.png",
      "winner": null
    },
    "away": {
      "id": 40,
      "name": "Liverpool",
      "logo": "https://media.api-sports.io/football/teams/40.png",
      "winner": null
    }
  },
  "goals": {
    "home": 2,
    "away": 1
  },
  "score": {
    "halftime": {
      "home": 1,
      "away": 0
    },
    "fulltime": {
      "home": 2,
      "away": 1
    },
    "extratime": {
      "home": null,
      "away": null
    },
    "penalty": {
      "home": null,
      "away": null
    }
  }
}
📋 Field Reference
FieldTypeMô tả
fixture.idintID trận đấu
fixture.refereestring|nullTrọng tài
fixture.timezonestringMúi giờ
fixture.datestringThời gian ISO 8601
fixture.timestampintUnix timestamp
fixture.periods.firstint|nullTimestamp bắt đầu hiệp 1
fixture.periods.secondint|nullTimestamp bắt đầu hiệp 2
fixture.venue.idintID sân vận động
fixture.venue.namestringTên sân
fixture.venue.citystringThành phố
fixture.status.longstringTrạng thái đầy đủ
fixture.status.shortstringMã trạng thái viết tắt
fixture.status.elapsedint|nullPhút đã chơi
fixture.status.extraint|nullPhút bù giờ
league.idintID giải đấu
league.namestringTên giải
league.countrystringQuốc gia
league.logostringURL logo giải đấu
league.flagstringURL cờ quốc gia
league.seasonintMùa giải
league.roundstringVòng đấu
teams.home.idintID đội nhà
teams.home.namestringTên đội nhà
teams.home.logostringURL logo đội nhà
teams.home.winnerbool|nullĐội nhà thắng (null = chưa kết thúc)
teams.away.idintID đội khách
teams.away.namestringTên đội khách
teams.away.logostringURL logo đội khách
teams.away.winnerbool|nullĐội khách thắng
goals.homeint|nullSố bàn thắng đội nhà
goals.awayint|nullSố bàn thắng đội khách
score.halftimeobjectTỷ số hiệp 1 (home, away)
score.fulltimeobjectTỷ số chung cuộc
score.extratimeobjectTỷ số hiệp phụ
score.penaltyobjectTỷ số loạt penalty
🏷️ Fixture Status Codes
TBD Chưa xác định
NS Chưa bắt đầu
1H Hiệp 1
HT Giữa giờ
2H Hiệp 2
ET Hiệp phụ
BT Nghỉ hiệp phụ
P Penalty
FT Kết thúc
AET KT sau hiệp phụ
PEN KT sau penalty
SUSP Tạm hoãn
INT Gián đoạn
PST Hoãn
CANC Hủy
ABD Hủy bỏ
AWD Xử thắng
WO Bỏ cuộc
LIVE Đang diễn ra
Fixture Events GET TTL: 60s
GET /fixtures/events?fixture={id}

Lấy danh sách sự kiện của trận đấu: bàn thắng, thẻ phạt, thay người, VAR...

⚙️ Query Parameters
ParamTypeRequiredMô tả
fixtureintrequiredFixture ID
📄 Response Model
JSON Response (mở rộng)
{
  "time": {
    "elapsed": 23,
    "extra": null
  },
  "team": {
    "id": 33,
    "name": "Manchester United",
    "logo": "https://media.api-sports.io/football/teams/33.png"
  },
  "player": {
    "id": 1234,
    "name": "Bruno Fernandes"
  },
  "assist": {
    "id": 5678,
    "name": "Marcus Rashford"
  },
  "type": "Goal",
  "detail": "Normal Goal",
  "comments": null
}
📋 Field Reference
FieldTypeMô tả
time.elapsedintPhút diễn ra sự kiện
time.extraint|nullPhút bù giờ (nếu có)
team.idintID đội liên quan
team.namestringTên đội
team.logostringURL logo đội
player.idintID cầu thủ
player.namestringTên cầu thủ
assist.idint|nullID cầu thủ kiến tạo
assist.namestring|nullTên cầu thủ kiến tạo
typestringLoại sự kiện (Goal, Card, subst, Var)
detailstringChi tiết sự kiện
commentsstring|nullGhi chú bổ sung
🏷️ Event Types & Details
typedetail values
GoalNormal Goal, Own Goal, Penalty, Missed Penalty
CardYellow Card, Red Card, Second Yellow card
substSubstitution 1, Substitution 2, Substitution 3, Substitution 4, Substitution 5, Substitution 6
VarGoal cancelled, Penalty confirmed
Fixture Lineups GET TTL: 120s
GET /fixtures/lineups?fixture={id}

Lấy đội hình ra sân, đội hình dự bị, sơ đồ chiến thuật và huấn luyện viên.

⚙️ Query Parameters
ParamTypeRequiredMô tả
fixtureintrequiredFixture ID
📄 Response Model
JSON Response (mở rộng)
{
  "team": {
    "id": 33,
    "name": "Manchester United",
    "logo": "https://media.api-sports.io/football/teams/33.png",
    "colors": {
      "player": {
        "primary": "#DA291C",
        "number": "#FFFFFF",
        "border": "#DA291C"
      },
      "goalkeeper": {
        "primary": "#1E1E1E",
        "number": "#FFFFFF",
        "border": "#1E1E1E"
      }
    }
  },
  "coach": {
    "id": 123,
    "name": "Erik ten Hag",
    "photo": "https://media.api-sports.io/football/coachs/123.png"
  },
  "formation": "4-2-3-1",
  "startXI": [
    {
      "player": {
        "id": 1,
        "name": "Onana",
        "number": 24,
        "pos": "G",
        "grid": "1:1"
      }
    }
  ],
  "substitutes": [
    {
      "player": {
        "id": 2,
        "name": "Bayindir",
        "number": 1,
        "pos": "G",
        "grid": null
      }
    }
  ]
}
📋 Field Reference
FieldTypeMô tả
team.idintID đội
team.namestringTên đội
team.logostringURL logo
team.colors.playerobjectMàu áo cầu thủ (primary, number, border)
team.colors.goalkeeperobjectMàu áo thủ môn
coach.idintID huấn luyện viên
coach.namestringTên HLV
coach.photostringURL ảnh HLV
formationstringSơ đồ chiến thuật (VD: "4-2-3-1")
startXI[].player.idintID cầu thủ
startXI[].player.namestringTên cầu thủ
startXI[].player.numberintSố áo
startXI[].player.posstringVị trí (G, D, M, F)
startXI[].player.gridstring|nullVị trí trên sân (row:col)
substitutesarrayCầu thủ dự bị (cùng cấu trúc)
🏷️ Position Values
G Thủ môn
D Hậu vệ
M Tiền vệ
F Tiền đạo
Fixture Statistics GET TTL: 60s
GET /fixtures/statistics?fixture={id}

Lấy thống kê trận đấu: sút bóng, kiểm soát bóng, phạm lỗi, thẻ phạt, xG...

⚙️ Query Parameters
ParamTypeRequiredMô tả
fixtureintrequiredFixture ID
📄 Response Model
JSON Response (mở rộng)
{
  "team": {
    "id": 33,
    "name": "Manchester United",
    "logo": "https://media.api-sports.io/football/teams/33.png"
  },
  "statistics": [
    { "type": "Shots on Goal", "value": 5 },
    { "type": "Ball Possession", "value": "55%" },
    { "type": "expected_goals", "value": "1.23" }
  ]
}
📋 Field Reference
FieldTypeMô tả
team.idintID đội
team.namestringTên đội
team.logostringURL logo
statistics[].typestringTên thống kê
statistics[].valueint|string|nullGiá trị thống kê
🏷️ Tất cả Stat Types
Shots on Goal
Shots off Goal
Total Shots
Blocked Shots
Shots insidebox
Shots outsidebox
Fouls
Corner Kicks
Offsides
Ball Possession
Yellow Cards
Red Cards
Goalkeeper Saves
Total passes
Passes accurate
Passes %
expected_goals
goals_prevented
💡
Lưu ý: Trường value có thể là int (VD: 5), string (VD: "55%"), hoặc null (chưa có dữ liệu).
Head to Head GET TTL: 1h
GET /fixtures/headtohead?h2h=33-40

Lấy lịch sử đối đầu giữa hai đội. Response trả về danh sách fixtures giống endpoint /fixtures.

⚙️ Query Parameters
ParamTypeRequiredMô tả
h2hstringrequiredFormat: TEAMID-TEAMID (VD: "33-40")
📌
Response có cùng cấu trúc với /fixtures — mỗi item là một FixtureResponse object.
Standings GET TTL: 15min
GET /standings?league=39&season=2024

Lấy bảng xếp hạng giải đấu. Kết quả nằm trong league.standings — là mảng các mảng (groups).

⚙️ Query Parameters
ParamTypeRequiredMô tả
leagueintrequiredLeague ID
seasonintrequiredMùa giải (VD: 2024)
📄 Response Model
JSON Response (mở rộng)
{
  "league": {
    "id": 39,
    "name": "Premier League",
    "country": "England",
    "logo": "https://media.api-sports.io/football/leagues/39.png",
    "flag": "https://media.api-sports.io/flags/gb-eng.svg",
    "season": 2024,
    "standings": [[
      {
        "rank": 1,
        "team": {
          "id": 40,
          "name": "Liverpool",
          "logo": "https://media.api-sports.io/football/teams/40.png"
        },
        "points": 84,
        "goalsDiff": 45,
        "group": "Premier League",
        "form": "DLDLW",
        "status": "same",
        "description": "Champions League",
        "all": {
          "played": 38,
          "win": 25,
          "draw": 9,
          "lose": 4,
          "goals": {
            "for": 86,
            "against": 41
          }
        },
        "home": {
          "played": 19,
          "win": 14,
          "draw": 4,
          "lose": 1,
          "goals": {
            "for": 42,
            "against": 16
          }
        },
        "away": {
          "played": 19,
          "win": 11,
          "draw": 5,
          "lose": 3,
          "goals": {
            "for": 44,
            "against": 25
          }
        },
        "update": "2025-05-26T00:00:00+00:00"
      }
    ]]
  }
}
📋 Field Reference
FieldTypeMô tả
league.idintID giải đấu
league.namestringTên giải
league.countrystringQuốc gia
league.seasonintMùa giải
league.standingsarray[][]Mảng 2 chiều — mỗi mảng con là 1 group
rankintThứ hạng
team.idintID đội
team.namestringTên đội
team.logostringURL logo
pointsintSố điểm
goalsDiffintHiệu số bàn thắng
groupstringTên bảng/nhóm
formstringPhong độ 5 trận gần nhất (W/D/L)
statusstringThay đổi thứ hạng (same/up/down)
descriptionstring|nullMô tả vị trí (Champions League, Relegation...)
allobjectThống kê tổng (played, win, draw, lose, goals)
homeobjectThống kê sân nhà
awayobjectThống kê sân khách
goals.forintSố bàn ghi được
goals.againstintSố bàn thua
updatestringThời gian cập nhật gần nhất
Teams GET TTL: 1 ngày
GET /teams?id=33

Lấy thông tin đội bóng và sân vận động.

⚙️ Query Parameters
ParamTypeRequiredMô tả
idintoptionalTeam ID
searchstringoptionalTìm kiếm theo tên (tối thiểu 3 ký tự)
📄 Response Model
JSON Response (mở rộng)
{
  "team": {
    "id": 33,
    "name": "Manchester United",
    "code": "MUN",
    "country": "England",
    "founded": 1878,
    "national": false,
    "logo": "https://media.api-sports.io/football/teams/33.png"
  },
  "venue": {
    "id": 556,
    "name": "Old Trafford",
    "address": "Sir Matt Busby Way",
    "city": "Manchester",
    "capacity": 76212,
    "surface": "grass",
    "image": "https://media.api-sports.io/football/venues/556.png"
  }
}
📋 Field Reference
FieldTypeMô tả
team.idintID đội
team.namestringTên đầy đủ
team.codestringMã viết tắt (3 ký tự)
team.countrystringQuốc gia
team.foundedintNăm thành lập
team.nationalboolĐội tuyển quốc gia?
team.logostringURL logo
venue.idintID sân
venue.namestringTên sân
venue.addressstringĐịa chỉ
venue.citystringThành phố
venue.capacityintSức chứa
venue.surfacestringBề mặt sân (grass, artificial turf...)
venue.imagestringURL ảnh sân
Leagues GET TTL: 1 ngày
GET /leagues?country=England

Lấy thông tin giải đấu, quốc gia, và các mùa giải có sẵn. Không truyền param = lấy tất cả.

⚙️ Query Parameters
ParamTypeRequiredMô tả
idintoptionalLeague ID cụ thể
countrystringoptionalLọc theo quốc gia
📄 Response Model
JSON Response (mở rộng)
{
  "league": {
    "id": 39,
    "name": "Premier League",
    "type": "League",
    "logo": "https://media.api-sports.io/football/leagues/39.png"
  },
  "country": {
    "name": "England",
    "code": "GB-ENG",
    "flag": "https://media.api-sports.io/flags/gb-eng.svg"
  },
  "seasons": [
    {
      "year": 2024,
      "start": "2024-08-16",
      "end": "2025-05-25",
      "current": true,
      "coverage": {
        "fixtures": {
          "events": true,
          "lineups": true,
          "statistics_fixtures": true,
          "statistics_players": true
        },
        "standings": true,
        "players": true,
        "top_scorers": true,
        "top_assists": true,
        "top_cards": true,
        "injuries": true,
        "predictions": true,
        "odds": false
      }
    }
  ]
}
📋 Field Reference
FieldTypeMô tả
league.idintID giải đấu
league.namestringTên giải
league.typestringLoại: "League" hoặc "Cup"
league.logostringURL logo
country.namestringTên quốc gia
country.codestringMã quốc gia
country.flagstringURL cờ
seasons[].yearintNăm mùa giải
seasons[].startstringNgày bắt đầu
seasons[].endstringNgày kết thúc
seasons[].currentboolMùa giải hiện tại?
coverage.fixturesobjectDữ liệu fixtures có sẵn
coverage.standingsboolCó bảng xếp hạng?
coverage.playersboolCó thống kê cầu thủ?
coverage.oddsboolCó tỷ lệ kèo?
Countries GET TTL: 7 ngày
GET /countries

Lấy danh sách tất cả quốc gia có giải đấu bóng đá. Không cần query params.

📄 Response Model
JSON Response (mở rộng)
{
  "name": "England",
  "code": "GB-ENG",
  "flag": "https://media.api-sports.io/flags/gb-eng.svg"
}
📋 Field Reference
FieldTypeMô tả
namestringTên quốc gia
codestringMã quốc gia (ISO)
flagstringURL cờ quốc gia (SVG)
Timezone GET TTL: 7 ngày
GET /timezone

Lấy danh sách tất cả timezone được API hỗ trợ. Response là mảng string đơn giản.

📄 Response
JSON Response (mở rộng)
[
  "Africa/Abidjan",
  "Africa/Accra",
  "America/New_York",
  "Asia/Ho_Chi_Minh",
  "Europe/London",
  "..."
]
Top Scorers & Assists GET TTL: 24h
GET /players/topscorers?league=39&season=2023

Lấy danh sách các cầu thủ ghi bàn / kiến tạo nhiều nhất của một giải đấu trong một mùa giải. Bạn có thể thay đổi endpoint thành /players/topassists, /players/topyellowcards, hoặc /players/topredcards để lấy thống kê tương ứng.

Query Parameters
Parameter Type Required Description
league Integer Yes ID của giải đấu (VD: 39 cho Premier League)
season Integer Yes Năm bắt đầu của mùa giải (VD: 2023)
📋 Field Reference
FieldTypeDescription
player.idintID của cầu thủ
player.namestringTên cầu thủ
statistics[0].team.namestringTên đội bóng
statistics[0].goals.totalint|nullTổng số bàn thắng
statistics[0].goals.assistsint|nullTổng số kiến tạo
statistics[0].cards.yellowint|nullSố thẻ vàng
statistics[0].cards.redint|nullSố thẻ đỏ
Injuries GET TTL: 24h
GET /injuries?fixture=1032731

Lấy danh sách các cầu thủ bị chấn thương, treo giò hoặc vắng mặt trong một trận đấu cụ thể (fixture), hoặc của một đội bóng.

Query Parameters
Parameter Type Required Description
fixture Integer No ID của trận đấu. Phải có ít nhất 1 tham số như fixture, team, hoặc league.
team Integer No ID của đội bóng
📋 Field Reference
FieldTypeDescription
player.idintID của cầu thủ
player.namestringTên cầu thủ
player.typestringTình trạng (Missing Fixture, Questionable...)
player.reasonstringLý do (Ankle Injury, Suspended...)
team.namestringTên đội bóng
fixture.datestringNgày diễn ra trận đấu
Transfers GET TTL: 24h
GET /transfers?team=33

Lấy lịch sử chuyển nhượng của một cầu thủ hoặc một đội bóng.

Query Parameters
Parameter Type Required Description
team Integer No ID của đội bóng (lấy danh sách chuyển nhượng của đội)
player Integer No ID của cầu thủ (lấy lịch sử chuyển nhượng của cầu thủ)
📋 Field Reference
FieldTypeDescription
player.namestringTên cầu thủ
transfers[].datestringNgày chuyển nhượng
transfers[].typestringLoại chuyển nhượng (Free, Loan, € 50M...)
transfers[].teams.in.namestringĐội mua / mượn (đến)
transfers[].teams.out.namestringĐội bán / cho mượn (đi)
Predictions GET TTL: 24h
GET /predictions?fixture=1208869

Lấy dữ liệu dự đoán, nhận định tỉ số, phong độ đối đầu và phân tích sức mạnh giữa hai đội trước một trận đấu.

Query Parameters
Parameter Type Required Description
fixture Integer Yes ID của trận đấu
📋 Field Reference
FieldTypeDescription
predictions.winner.namestringTên đội dự đoán sẽ thắng
predictions.advicestringLời khuyên / Nhận định chung (Tiếng Anh)
predictions.percent.homestringTỉ lệ thắng của đội nhà (%)
predictions.percent.drawstringTỉ lệ hòa (%)
predictions.percent.awaystringTỉ lệ thắng của đội khách (%)
comparison.form.homestringChỉ số phong độ đội nhà
comparison.total.homestringĐiểm sức mạnh tổng hợp đội nhà

💻 Code Examples

Ví dụ tích hợp đầy đủ cho các ngôn ngữ phổ biến. Copy & paste để bắt đầu ngay.

import Foundation

// MARK: - Configuration
let baseURL = "https://football-proxy-internal.manhpd-football.workers.dev"

// MARK: - API Client
func apiRequest(_ path: String) async throws -> Data {
    guard let url = URL(string: "\(baseURL)\(path)") else {
        throw URLError(.badURL)
    }
    var request = URLRequest(url: url)
    request.timeoutInterval = 30
    
    let (data, response) = try await URLSession.shared.data(for: request)
    
    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        throw URLError(.badServerResponse)
    }
    return data
}

// MARK: - Live Matches
func fetchLiveMatches() async throws -> [String: Any] {
    let data = try await apiRequest("/fixtures?live=all")
    guard let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] else {
        throw URLError(.cannotParseResponse)
    }
    return json
}

// MARK: - Standings
func fetchStandings(league: Int, season: Int) async throws -> Data {
    return try await apiRequest("/standings?league=\(league)&season=\(season)")
}

// MARK: - Usage
Task {
    do {
        let matches = try await fetchLiveMatches()
        print("Results: \(matches["results"] ?? 0)")
    } catch {
        print("Error: \(error.localizedDescription)")
    }
}
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query

// Configuration
const val BASE_URL = "https://football-proxy-internal.manhpd-football.workers.dev"

// API Interface
interface FootballApi {
    @GET("/fixtures")
    suspend fun getLiveMatches(@Query("live") live: String = "all"): ApiResponse
    
    @GET("/standings")
    suspend fun getStandings(
        @Query("league") league: Int,
        @Query("season") season: Int
    ): ApiResponse
    
    @GET("/teams")
    suspend fun getTeam(@Query("id") id: Int): ApiResponse
}

// Client Setup
val client = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val request = chain.request().newBuilder()
            .build()
        chain.proceed(request)
    }
    .build()

val api: FootballApi = Retrofit.Builder()
    .baseUrl(BASE_URL)
    .client(client)
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    .create(FootballApi::class.java)

// Usage
suspend fun main() {
    try {
        val matches = api.getLiveMatches()
        println("Live: ${matches.results} matches")
    } catch (e: Exception) {
        println("Error: ${e.message}")
    }
}
const BASE_URL = 'https://football-proxy-internal.manhpd-football.workers.dev';

// API Helper
async function api(path) {
  const res = await fetch(`${BASE_URL}${path}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// Live Matches
async function getLiveMatches() {
  const data = await api('/fixtures?live=all');
  console.log(`Live: ${data.results} matches`);
  return data.response;
}

// Standings
async function getStandings(league, season) {
  const data = await api(`/standings?league=${league}&season=${season}`);
  return data.response;
}

// Usage
try {
  const matches = await getLiveMatches();
  const standings = await getStandings(39, 2024);
} catch (err) {
  console.error('API Error:', err.message);
}
import 'dart:convert';
import 'package:http/http.dart' as http;

const baseUrl = 'https://football-proxy-internal.manhpd-football.workers.dev';

// API Helper
Future<Map<String, dynamic>> api(String path) async {
  final response = await http.get(Uri.parse('$baseUrl$path'));
  if (response.statusCode != 200) {
    throw Exception('HTTP ${response.statusCode}');
  }
  return jsonDecode(response.body);
}

// ==========================================
// 1. DATA MODELS
// ==========================================

class Fixture {
  final int id;
  final String date;
  final int timestamp;
  final Status status;
  
  Fixture.fromJson(Map json)
      : id = json['id'],
        date = json['date'],
        timestamp = json['timestamp'],
        status = Status.fromJson(json['status']);
}

class Status {
  final String long;
  final String short;
  final int? elapsed;
  
  Status.fromJson(Map json)
      : long = json['long'],
        short = json['short'],
        elapsed = json['elapsed'];
}

class Team {
  final int id;
  final String name;
  final String logo;
  final bool? winner;
  
  Team.fromJson(Map json)
      : id = json['id'],
        name = json['name'],
        logo = json['logo'],
        winner = json['winner'];
}

class FixtureMatch {
  final Fixture fixture;
  final Team home;
  final Team away;
  final int? homeGoals;
  final int? awayGoals;
  
  FixtureMatch.fromJson(Map json)
      : fixture = Fixture.fromJson(json['fixture']),
        home = Team.fromJson(json['teams']['home']),
        away = Team.fromJson(json['teams']['away']),
        homeGoals = json['goals']['home'],
        awayGoals = json['goals']['away'];
}

// ==========================================
// 2. API CALLS
// ==========================================

Future<List<FixtureMatch>> getLiveMatches() async {
  final response = await http.get(Uri.parse('$baseUrl/fixtures?live=all'));
  
  if (response.statusCode == 200) {
    final Map<String, dynamic> data = jsonDecode(response.body);
    final List<dynamic> items = data['response'];
    return items.map((e) => FixtureMatch.fromJson(e)).toList();
  } else {
    throw Exception('Failed to load matches');
  }
}

// Usage
void main() async {
  try {
    final matches = await getLiveMatches();
    for (var match in matches) {
      print('${match.home.name} ${match.homeGoals} - ${match.awayGoals} ${match.away.name}');
    }
  } catch (e) {
    print('Error: $e');
  }
}
import requests

BASE = 'https://football-proxy-internal.manhpd-football.workers.dev'

def api(path):
    """Call Football API Proxy"""
    r = requests.get(f'{BASE}{path}', timeout=30)
    r.raise_for_status()
    return r.json()

# Live Matches
def get_live_matches():
    data = api('/fixtures?live=all')
    print(f"Live: {data['results']} matches")
    return data['response']

# Standings  
def get_standings(league, season):
    data = api(f'/standings?league={league}&season={season}')
    return data['response']

# Usage
if __name__ == '__main__':
    try:
        matches = get_live_matches()
        standings = get_standings(39, 2024)
    except requests.RequestException as e:
        print(f'Error: {e}')
# Configuration
BASE="https://football-proxy-internal.manhpd-football.workers.dev"

# Health Check
curl -s "$BASE/__health" | jq .

# Live Matches
curl -s "$BASE/fixtures?live=all" | jq .

# Standings
curl -s "$BASE/standings?league=39&season=2024" | jq .

# Teams
curl -s "$BASE/teams?id=33" | jq .

# With verbose output (see headers)
curl -v "$BASE/fixtures?live=all"

# Check cache headers
curl -s -D- "$BASE/fixtures?live=all" | head -20

⚡ Cache Strategy

Hệ thống cache multi-layer sử dụng Cloudflare KV với Stale-While-Revalidate pattern.

📊 Cache TTL theo Endpoint
EndpointTTLGrace PeriodTotal Edge TTL
/fixtures (live)30s30s60s
/fixtures (date/id)60s60s120s
/fixtures/events60s60s120s
/fixtures/lineups120s60s180s
/fixtures/statistics60s60s120s
/fixtures/headtohead3600s600s4200s
/featured300s120s420s
/standings900s300s1200s
/teams86400s3600s90000s
/leagues86400s3600s90000s
/countries604800s86400s691200s
/timezone604800s86400s691200s
🔄 Stale-While-Revalidate Pattern

Khi cache fresh: trả về ngay, không gọi API gốc.
Khi cache stale (TTL hết nhưng còn trong grace period): trả về dữ liệu cũ ngay lập tức, đồng thời gọi API gốc để cập nhật cache ở background.
Khi cache expired (quá cả grace period): gọi API gốc, chờ response, lưu cache, rồi trả về.

📡 Cache Response Headers
HeaderValuesMô tả
X-CacheHIT | MISSDữ liệu từ cache hay từ API gốc
X-Cache-Statefresh | stale | expiredTrạng thái cache hiện tại
X-Cache-TTLnumber (seconds)Số giây còn lại trước khi cache hết hạn

🔒 Bảo mật

4 lớp bảo mật bảo vệ Worker khỏi truy cập trái phép.

🛡️

App Check

Firebase App Check xác minh request đến từ app hợp lệ, ngăn chặn bot và request giả mạo.

🔑
📋

Path Allowlist

Chỉ các path được phép mới được proxy. Tất cả path khác trả về 403 Forbidden.

🌐

CORS

Chỉ cho phép request từ các origin đã được cấu hình. Ngăn chặn cross-origin request từ domain lạ.

🌐 Multi-Project

Sử dụng Cloudflare Environments để quản lý nhiều dự án với cùng một codebase.

Mỗi project có thể có environment riêng trong wrangler.toml, với domain/subdomain riêng, KV namespace riêng, và API key riêng.

📄 Ví dụ wrangler.toml
[env.livescore]
name = "football-proxy-livescore"
route = "livescore-proxy.example.com/*"
kv_namespaces = [
  { binding = "CACHE", id = "abc123" }
]

[env.betapp]
name = "football-proxy-betapp"
route = "betapp-proxy.example.com/*"
kv_namespaces = [
  { binding = "CACHE", id = "def456" }
]
💡
Deploy cho project cụ thể: wrangler deploy --env livescore

🚀 Self-host Setup

3 bước để deploy Worker của riêng bạn.

1

Clone & Install

git clone <repo-url>
cd football-proxy
npm install

2

Login & Set Secret

wrangler login
npm run secret
(Nhập API key từ api-football.com)

3

Deploy

npm run deploy
Worker sẽ được deploy lên Cloudflare Edge toàn cầu.

⚠️ Xử lý lỗi

Các lỗi thường gặp và cách khắc phục.

StatusNguyên nhânGiải pháp
401 Thiếu hoặc sai token
403 Path không được phép Kiểm tra path có nằm trong allowlist không
404 Endpoint không tồn tại Kiểm tra lại URL, tham khảo API Reference
429 Rate limit exceeded Giảm tần suất gọi API, sử dụng cache phía client
500 Lỗi server (Worker) Kiểm tra logs với wrangler tail
502 API-Football không phản hồi Thử lại sau vài giây, kiểm tra API-Football status
503 Service unavailable Kiểm tra Cloudflare Status

🔧 Lệnh hay dùng

Các lệnh thường dùng khi phát triển và quản lý Worker.

LệnhMô tả
npm installCài đặt dependencies
npm run devChạy local development server
npm run deployDeploy Worker lên Cloudflare
npm run tailXem logs realtime từ Worker đang chạy
npm run secretSet API key bí mật (API_FOOTBALL_KEY)
wrangler whoamiKiểm tra tài khoản Cloudflare đang đăng nhập
wrangler kv:listLiệt kê tất cả KV namespaces
wrangler kv:key list --binding=CACHEXem danh sách keys trong cache KV

Football API Proxy · Tài liệu nội bộ · Cập nhật 2025