ABFut
🇬🇧EN

Content API

The HTTP contract for publishing ABFut articles and trading tips, including every in-app deeplink a tip can use. Generated from the running server code.

Generated from the running server code on . Numbers, enums and the deeplink list on this page are read straight out of the validator the server runs — not copied by hand. Machine-readable version: /api/contract.json.

Authentication

Every write call needs a bearer token in the header. There is no self-service signup: ask for a key and you get one scoped to just the endpoints you need.

Authorization: Bearer <key>
Content-Type: application/json

A key carries scopes. A key scoped to post:tip cannot publish articles, and vice versa — so a leaked key is limited to the one job it was issued for. Keys are stored as hashes, so they are shown once at creation and can be revoked individually without disturbing any other caller.

Authentication errors

codemeaning
401 thiếu Authorization: Bearerthe header is missing
401 chứng thực không hợp lệwrong key, or it has been revoked
401 khoá không có phạm vi "…"valid key, but not allowed on this endpoint

Endpoints

endpointwhat it doesscope
POST /postArticlePublish an article — on the in-app wall at once, on the website at the next build.post:article
POST /postTipPublish a TIPS post — shows up in the app's Tips tab immediately.post:tip
GET /newsFeedRead published articles back. Public, no key needed.no
GET /sbcList?limit=50&sau=The whole SBC table, paginated by docId (50 per page max). Pass the previous page's `tiep` as `sau` for the next one.no
GET /sbcMeta?ten=Look up one SBC's cost and details by name. Omit `ten` to list the available names.no

endpoint: https://us-central1-ab-fut.cloudfunctions.net

postArticle — articles

An article lands on the in-app wall immediately. The website is static, so it appears there at the next build.

fieldrequiredlimits
titleyes10–120 characters
bodyyes80–6000 characters
tagsno≤ 5 items, ≤ 24 characters each; EAFC27 is added by the server
imageUrlnomust be https://, ≤ 400 characters
imageRationonumber, defaults to 1.91
authorNameno≤ 40 characters, defaults to ABFut News
langnoen | vi | es | fr, defaults to en
slugGocfor translationsthe slug of the English version
curl -X POST https://us-central1-ab-fut.cloudfunctions.net/postArticle \
  -H "Authorization: Bearer $ABFUT_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "title": "EA confirms TOTW 3 release time",
    "body":  "...",
    "tags":  ["Promo", "TOTW"],
    "imageUrl": "https://..."
  }'

Writing the body

The same string is both the website article and the in-app wall post. Write it for the wall and the website takes care of itself:

  • 200–350 words. Longer than that reads as a wall of text on the wall.
  • The first two or three sentences must stand alone — that is all a scrolling reader sees.
  • End on one concrete action, not a sign-off.

Markup the website renders

examplemeaning
boldbold
a line containing only Headingan <h2>
• bulleta list item
a YouTube link alone on its linean embedded player

Languages

The app and the website filter by language and do not fall back to English. An article that exists only in en is simply missing for everyone else.

Publish the English original first, keep the slug it returns, then send each translation with that slug as slugGoc. That pair is what ties the versions into one article and gets hreflang right; without it search engines read them as separate, duplicated pages.

Translations are exempt from the duplicate-topic rule — they are deliberately about the same thing.

-d '{ "title": "...", "body": "...", "lang": "vi",
      "slugGoc": "<slug of the English version>" }'

What the server rejects

codemeaningwhat to do
400missing field, too short, imageUrl not httpsfix the payload
409same topic already published within 7 days (the older post comes back in the response)change the angle, or drop it
42910 articles already published in 24 hourswait
503recent posts could not be readdo not publish; retry later

postTip — trading tips

A tip shows up in the app's Tips tab immediately; no website build needed. Posting the same (slug, lang) pair again overwrites rather than creating a second post.

fieldrequiredlimits
slugyesshared by every language of the same post
langyesen vi es fr
loaiyesleak promo thi_truong meo canh_bao
doTinCayyestin_don xac_nhan
tieuDeyes≤ 90
tomTatyes≤ 160 — this is the line shown in the list
thanyes—
hetHanyesISO date, must be in the future
anhnohttps://
chiPremiumnotrue / false
hanhDongnoactions, at post level
ynothe entries array

The y[] array is where the value is

than is prose a reader skims. Each entry in y[] is a card they can act on: a direction, a price range, one reason, and buttons.

fieldrequiredlimits
the.tenyescard name as futbin stores it
viSaoyesone sentence of reason
huongyesmua ban giu tranh theo_doi
doChacChanyescao vua thap
vungGiano{ tu, den } — both > 0 and tu ≤ den
hanhDongnoDeeplinks
{
  "the": { "ten": "Hadj Moussa" },
  "huong": "mua",
  "doChacChan": "vua",
  "viSao": "TOTW price dipped once packs dried up; floor around 9.5K.",
  "vungGia": { "tu": 9500, "den": 11000 },
  "hanhDong": [
    { "kieu": "xem_gia", "nhan": "Price", "uri": "abfut://player?id=70726" },
    { "kieu": "them_filter", "nhan": "Add to autobuy",
      "uri": "abfut://filter?player=70726&buy=9500&sell=11000" }
  ]
}

Spell card names the way futbin stores them — Groß, not Gross. Get it right and the server resolves the eaId at publish time so the price button is ready; get it wrong and the app has to search by name when the reader taps, which is slower and can miss entirely.

A direction of tranh (avoid) is a valid entry. A post about a card being pumped that only carries mua entries is pointing readers at the danger.

Tip buttons open the app through these URIs. The list is closed: a kieu that is not below, or a uri that does not match its shape, is rejected with 400 at publish time — and if one ever got through, the app would silently not draw the button.

Each action is an object:

{ "kieu": "...", "nhan": "button label", "uri": "..." }
kieuuri shapeconditionsexample
xem_giaabfut://player?id=<eaId>id > 0abfut://player?id=70726
them_filterabfut://filter?player=<id>&buy=<price>&sell=<price>player>0 | style>0 · buy>0 | bid>0 · sell>0abfut://filter?player=70726&buy=9500&sell=11000
mo_fodderabfut://fodder?rating=<N>81 ≤ N ≤ 99abfut://fodder?rating=89
mo_marketabfut://market—abfut://market
mo_sbcabfut://sbc | abfut://sbc_solution—abfut://sbc
mo_webhttps://abfut.site/...host = abfut.site | *.abfut.sitehttps://abfut.site/news/
mo_tababfut://player_tab?ten=<tab name>ten ≠ ""abfut://player_tab?ten=TOTW

xem_gia Opens the card page: price chart plus a button to add it straight to autobuy. id is the eaId, not the futbin id. If you do not have it, leave this action out — the server fills it in from y[].the.ten at publish time.

them_filter Adds a filter straight into autobuy — the strongest action here: one tap and the bot starts buying. So buy/sell must be real numbers from the source, and sell must clear buy by enough to survive EA's 5% tax; under ~8% the engine lowers or skips it. Use style=<id> instead of player=<id> when the advice is about a chem style, and bid instead of buy to bid rather than buy now.

mo_fodder Opens the fodder screen at that rating. If the post mentions fodder ratings, it needs one of these per rating — mention 89 and 90 and that is two separate buttons.

mo_market Opens the market price screen. For posts about overall price trends.

mo_sbc Opens the SBC screen or SBC solutions. For posts about a new SBC.

mo_web abfut.site only. futbin, YouTube and every other host is rejected. To point somewhere else, put the link in than as text.

mo_tab Opens one tab of the Players screen. ten is matched against the tab title, case-insensitively, trimmed. The tab set lives in Firestore (config/player_tabs) so it can change — the current list is in the table below. A name that matches no tab leaves the app on the tab it is already showing: the button reports no error, it simply does nothing. The server cannot catch this one, so it is on you to check.

Player screen tabs

Names accepted by mo_tab. Matched against the tab title case-insensitively. This set lives in Firestore, so it can change — this list is read at build time.

name
Market
<50K
Fastest
Icon
50-100K
Most Expensive
Meta
TOTW

newsFeed — reading back

Public, no key. Use it to check that a post went up and to avoid repeating a topic.

curl "https://us-central1-ab-fut.cloudfunctions.net/newsFeed?lang=vi&limit=20"
curl "https://us-central1-ab-fut.cloudfunctions.net/newsFeed?slug=<slug>"
parameterdefaultmeaning
langallone of the languages above
limit20max 50
slug—matches slug or slugGoc

Returns { ok, lang, soBai, bai: [...] }. Edge-cached for 5 minutes, so something just published may not appear yet.

sbcMeta — SBC costs

Public, no key. Returns the crawled futbin figures for one SBC: cost on console and PC, whether it repeats, when it expires, the community vote.

curl --get "https://us-central1-ab-fut.cloudfunctions.net/sbcMeta" --data-urlencode "ten=83+ Upgrade"
curl "https://us-central1-ab-fut.cloudfunctions.net/sbcMeta"      # list the names

The name is matched in three steps, strictest first: the exact document key, then ignoring case, then ignoring everything that is not a letter or digit (so 83 upgrade finds 83+ Upgrade).

A name that matches none of them returns 404 with a goiY list of close names — it never picks the closest one for you. These are coin costs: answering about a different SBC is worse than answering nothing. Call it with no ten to list every name available.

To label many SBCs at once — an overlay on EA's SBC screen, for example — use sbcList instead and match locally: one request for the whole table rather than one per name, and re-renders then cost nothing. Page through it by passing the previous response's tiep back as sau; tiep: null means that was the last page. Mirror the three matching steps above locally so a name does not resolve one way here and another way there.

curl "https://us-central1-ab-fut.cloudfunctions.net/sbcList?limit=50"
curl --get "https://us-central1-ab-fut.cloudfunctions.net/sbcList" -d limit=50 \
     --data-urlencode "sau=<tiep>"

Rules

  • Do not invent numbers. Every price, percentage and card name has to come from the source. A wrong price costs a reader real coins.
  • Do not promise profit. No "guaranteed", no "double your coins". ABFut's own FAQ answers "Does ABFut guarantee profit? No" — writing the opposite contradicts it, and app stores scrutinise earnings claims closely.
  • Expiry is mandatory on tips. Advice to "buy before Friday" still sitting in the feed on Monday is advice that is now wrong.

Guides and tactics pages live in the repository and have no API — draft the content and hand it over.