· 6 years ago · Jan 21, 2020, 10:14 PM
1
2CFBackend API
3
4The term "CFB-API" or "CFAPI" is being used to refer to the API in this document.
5
6The CFAPI is the successor of all current API implementations and effectively replaces the existing DDNBackend API and Omega ServiceAPI.
7Basics
8
9All API requests must contain a Client-ID header.
10
11This Client-ID can be retrieved from the API control panel or can be CFBackendAPIClient when not logged in and requesting the API index.
12
13The User-Agent header should represent the requestor in a formly manor and should contain a contact website.
14It must be sent in following format: User-Agent: https://example.org (email@example.org)
15
16API URL Base: https://cfbackend.de
17
18Specific API endpoints require specific authorization levels. When requiring a higher authorization level contact our SupportCenter.
19
20To gain access to billable API endpoints please contact our SupportCenter.
21Rate-limits
22
23The Floodgate subsystem handles rate limitation for the CFBackend API.
24Default rate limit
25
26The default rate limit is 20 requests per 3 seconds per snowflake including a overall rate limit of 1.000 requests per 3 seconds.
27Rate-limit snowflakes
28
29Floodgate differentiates requests based on authenticated applicationid, so every applicationid has its own rate limit window tied to the requestor ip address.
30
31Each application can have its own rate limit, with an additional overall ip address rate limit.
32
33Requests blocked due to rate-limiting dont count towards the global requests scope.
34API response headers
35
36Floodgate will add two HTTP headers to the API response:
37
38Floodgate-Global-Remaining
39Floodgate-Snowflake-Remaining
40
41Which contain the remaining request count, before the rate-limit kicks in.
42Authentication
43Basics
44
45Authentication is done by sending a POST request to https://cfbackend.de/auth/login.
46The request body must contain a secret.
47
48secret Is a hashed string following this format: sha256(*plain_secret*) (Without *)
49
50The API responds with both an access_token and a refresh_token. Every access token is valid for 24 hours and needs to be refreshed afterwards. The API won't transmit the access token expiry date as refresh handling should be implemented on your side.
51
52Each API application can only have one active access_token. When creating a new one, all currently existing tokens are being invalidated.
53
54Login URL: https://cfbackend.de/auth/login
55Refresh URL: https://cfbackend.de/auth/refresh
56
57Login:
58
59curl -XPOST -H 'User-Agent: https://example.org (email@example.org)' -H 'Client-ID: example' -H "Content-type: application/json" -d '{"secret": "..."}' 'https://cfbackend.de/auth/login'
60
61=>
62
63{
64 "access_token":"...",
65 "refresh_token":"...",
66 "status":true
67}
68
69Authenticated requests must contain the access_token as authorization header.
70Example: Authorization: Bearer eyAdsAk192091ssInR5c....
71
72To access the refresh endpoint the authorization header must contain the refresh_token instead of the access_token.
73Service tokens
74
75Service tokens are a special token created by the service owner for a specific application.
76
77The service tokens only allow the access for one service for the specific registered api application.
78
79Each token can be individually deactivated and stats are being tracked.
80Service token retrieval
81
82The avaialable service tokens can be retrieved by accessing:
83[GET] /v1/servicetokens
84
85It will return a list of currently active service tokens including their service_id they have been issued for.
86
87Response:
88
89{
90 "status": true,
91 "tokens": [
92 {
93 "service_id": "5b74211ac221d55ecb1ddaea",
94 "token": "58188e63a2145f85cd0410...",
95 "token_id": "5caded8a..."
96 }
97 ]
98}
99
100Application information
101
102To retrieve information about your current API client you may request :
103[GET] /v1/application
104
105Response:
106
107{
108 "status": true,
109 "application": {
110 "application_id": "5c8d651dd6...",
111 "integrity_token": "9449d79a8201a9521cf...",
112 "total_requests": 5337
113 },
114 "floodgate": {
115 "last_request": 0,
116 "limit": 20,
117 "snowflakes": {
118 "...": 0
119 },
120 "window_start": 0
121 },
122 "request": {
123 "ip": "...",
124 "user_agent": "... (5c8d651dd6...)"
125 }
126}
127
128Authorization
129
130Specific endpoints require special authorization which can be acquired by contacting our SupportCenter.
131
132These special permissions are not guaranteed to be provided and the process is being decided on a case-to-case basis.
133Endpoints
134
135This is an incomplete list of all available scopes and endpoints. The full and always up to date list can be found by requesting [GET] https://cfbackend.de/.
136
137When asking for help/support please include the function reference you receive via this endpoint.
138Whitelist
139
140The whitelist endpoints are universal and accessible by any valid service token as the whole white and banlist system are available throughout all available platforms.
141list
142
143[GET] /v1/whitelist/<service_token>/list
144
145Returns the complete list of currently active whitelist entries.
146This may be not the actual service whitelist as whitelist sharding effectively overwrides the base whitelist system.
147
148Demo response:
149
150
151Omega
152servicestatus
153
154[GET] /v1/omega/servicestatus
155
156Returns current service status
157
158For base auth level the individual node status can only be ok or critical
159
160Demo response:
161
162{
163 "status": true,
164 "nodes": {
165 "drainheart": "ok",
166 "dragonbane": "ok",
167 "dawnbreaker": "ok",
168 "bloodscythe": "ok",
169 "oathblade": "ok"
170 },
171 "webinterfaces": {
172 "omegaweb": "ok"
173 }
174}
175
176leaderboard
177
178[GET] /v1/omega/<service_token>/leaderboard
179Arguments: order stat limit
180Orders: ascending descending
181Stat types: kills deaths playtime
182Limit: Integer between 1 and 100
183
184Returns stat leaderboards
185
186playtime Playtime in seconds
187latest_name Latest name (can be Ingame or Steam profile name)
188rank Internal rank index (Results may be unordered)
189
190The bigger the playerpool the higher the execute duration.
191
192Results for this endpoint are being cached for 5 minutes and a special rate limit is in place. (1 request per 1 minute)
193
194When the query duration exceeds 10s the execution will be stopped and a field incomplete will be set to true.
195
196Demo response:
197
198{
199 "duration": "103.63ms",
200 "query": {
201 "service_id": "5b74211ac221d55ecb1ddaea",
202 "stat": "playtime",
203 "limit": 1,
204 "order": {
205 "int": -1,
206 "string": "descending"
207 }
208 },
209 "status": true,
210 "users": [
211 {
212 "playtime": 592,
213 "cftools_id": "5b741963c221d558724f2355",
214 "latest_name": "philipp",
215 "rank": 1
216 }
217 ]
218}
219
220Lookup
221steam64
222
223[GET] /v1/lookup/<battleye_guid>/steam64
224
225Arguments: extensive
226Extensive: 1 0
227If not present in HA DB fallback to much slower fallback DB (It is not recommended to use this for each and every request as the fallback DB query can take up to 60s to complete)
228
229Convert BattlEye GUID to Steam64. Invalid/spoofed BattlEye GUIDs will return an error.
230
231This endpoint is limited
232IP
233resolve
234
235[GET] /v1/ip/<IPv4>/steam64
236
237Arguments: full
238Full: true false
239
240Return information about provided IP address.
241
242This endpoint is limited, with a trial available of 100 queries per month.
243The data returned by this endpoint may contain data provided by MaxMind.
244This endpoint may not be used to resolve user IP addresses but rather get information about server systems.
245Abusing/reselling this information is not allowed.
246
247Response:
248
249{
250 "notice": "May contain data created by MaxMind, available from http://www.maxmind.com.",
251 "status": true,
252 "extensive": true,
253 "host": {
254 "error": "not_available",
255 "status": false
256 },
257 "ip": "...",
258 "location": {
259 "city_name": null,
260 "country_code": "DE",
261 "country_name": "Germany",
262 "region": null,
263 "success": true,
264 "timezone": null,
265 "delta": 0.966064453125,
266 "delta_string": "0.97"
267 },
268 "timezone": {
269 "daylight_savings_time": true,
270 "success": true,
271 "time_24": "11:42",
272 "timestamp": 1555580545.0,
273 "zone": "Europe/Berlin"
274 }
275}
276
277SteamWorkshop
278
279The Steam Workshop scope offers functions to query the internal Steam Workshop tracking database.
280games
281
282[GET] /v1/workshop/apps
283
284Returns a list of all supported Steam apps
285
286Response:
287
288{
289 "status": true,
290 "total_entries": 50944,
291 "supported_games": [
292 {
293 "platform": "omega",
294 "game": "dayz",
295 "gamedir": "dayz",
296 "steam": {
297 "server_appid": 223350,
298 "game_appid": 221100
299 },
300 "nicename": "DayZ Standalone"
301 },
302 {
303 "platform": "omega",
304 "game": "arma3",
305 "gamedir": "arma3",
306 "steam": {
307 "server_appid": 233780,
308 "game_appid": 107410
309 },
310 "nicename": "Arma 3"
311 }
312 ],
313 "available_app_ids": [
314 107410,
315 221100
316 ]
317}
318
319list
320
321[GET] /v1/workshop/<app_id>/list
322
323Returns a list of all workshop items for that app_id.
324
325The items field is a lazy generated data field and the response may be a stream.
326
327Response:
328
329{
330 "items": [
331 {
332 "app_id": 221100,
333 "created_at": 1556667686.3432515,
334 "favorited": 0,
335 "file_created": 1548887672,
336 "file_id": 1640167361,
337 "file_updated": 1549144215,
338 "flags": 5632,
339 "followers": 0,
340 "lifetime_subscriptions": 835,
341 "preview_url": "https://steamuserimages-a.akamaihd.net/ugc/954103393107915513/6AE9BE0C876191FA53590A69E7535A169809B71C/",
342 "size": "744038",
343 "storage_id": "5cc8dd26a1db3a1a8112ff1e",
344 "subscriptions": 10,
345 "title": "CFTools Shirt",
346 "updated_at": 1556705239.5076737,
347 "views": 335
348 }
349 ],
350 "status": true
351}
352
353Servers
354
355The server scope offers serverlists for all supported games.
356games
357
358[GET] /v1/servers/games
359
360Returns all available games
361
362Response:
363
364{
365 "available_games": [
366 "dayz"
367 ],
368 "status": true,
369 "supported_games": [
370 {
371 "game": "dayz",
372 "gamedir": "dayz",
373 "nicename": "DayZ Standalone",
374 "platform": "omega",
375 "server_count": 2571,
376 "steam": {
377 "game_appid": 221100,
378 "server_appid": 223350
379 }
380 }
381 ],
382 "total_servers": 2571
383}
384
385ataddress
386
387[GET] /v1/servers/<host>/ataddress
388
389Returns server found at addresses
390
391Optional arguments: game_port steam_query_port
392
393Response:
394
395{
396 "delta": 0.06,
397 "query": {
398 "game_port": false,
399 "steam_query_port": false
400 },
401 "results": 1,
402 "servers": [
403 {
404 "created_at": 1557129993,
405 "game": "dayz",
406 "gameserver": {
407 "environment": {
408 "gametime": "06:05",
409 "hive": "private",
410 "official": false,
411 "shard": "localdb"
412 },
413 "map": "chernarusplus",
414 "max_players": 4,
415 "mods": {
416 "available": false,
417 "count": 0,
418 "endpoint": "http://85.131.155.68:2312",
419 "list": [ ]
420 },
421 "name": "CFTools #1 / Testing",
422 "players": 0,
423 "settings": {
424 "night_time_acceleration": 0.0,
425 "third_person": true,
426 "time_acceleration": 30.0
427 },
428 "version": "1.02.151010"
429 },
430 "general": {
431 "addr": [
432 "85.131.155.68",
433 2302
434 ],
435 "flags": "battleye,external,privHive,shard,lqs0,etm2.000000,entm30.000000,06:05",
436 "geolocation": {
437 "city_name": null,
438 "country_code": "DE",
439 "country_name": "Germany",
440 "region": null,
441 "success": true,
442 "timezone": null
443 },
444 "host": "85.131.155.68",
445 "os": "windows",
446 "port": 2302
447 },
448 "online": true,
449 "security": {
450 "battleye": true,
451 "vac": true
452 },
453 "server_id": "be5c437cc3c98830abf26983e75b07c847e17886da5cafff56d3d2eda21564bd",
454 "status": {
455 "downtime": 0,
456 "existence": 93605,
457 "uptime": 100
458 },
459 "steam": {
460 "appid": 221100,
461 "product": "dayz",
462 "query_port": 2303,
463 "server_id": "90125608470230027"
464 },
465 "updated_at": 1557223499
466 }
467 ],
468 "status": true
469}
470
471list
472
473[GET] /v1/servers/<game>/list
474
475Returns server list for game
476
477Arguments: history, mods, limit
478history, mods: true or false
479limit: Integer between 1 and 10.000
480
481The returned datastructure for gameserver varies by game
482
483downtime is the total downtime recorded in seconds
484uptime represents the total recorded uptime as value in percent
485
486Response:
487
488{
489 "query": {
490 "history": false,
491 "limit": 1,
492 "mods": false,
493 "stats": false
494 },
495 "results": 1,
496 "servers": [
497 {
498 "created_at": 1556270531.5526218,
499 "game": "dayz",
500 "gameserver": {
501 "battleye": true,
502 "gametime": [
503 "15:49"
504 ],
505 "map": "chernarusplus",
506 "max_players": 100,
507 "os": 1,
508 "players": 2,
509 "public": false,
510 "tags": [
511 "battleye",
512 "external",
513 "privHive",
514 "shard",
515 "lqs0",
516 "15:49"
517 ],
518 "vac": true,
519 "version": "1.02.151010"
520 },
521 "host": "85.131.155.68",
522 "port": 2302,
523 "server_id": "be5c437cc3c98830abf26983e75b07c847e17886da5cafff56d3d2eda21564bd",
524 "server_name": "CFTools #1 | Testing",
525 "status": true,
526 "steam": {
527 "query_port": 27016,
528 "steamid": "90125333593443331"
529 },
530 "updated_at": 1556297938
531 }
532 ],
533 "status": true
534}
535
536details
537
538[GET] /v1/servers/<server_id>/details
539
540server_id is in the following format: sha256('{{host}}{{gameport}}{{steam_query_port}}')
541
542The returned datastructure for gameserver varies by game
543
544downtime is the total downtime recorded in seconds
545uptime represents the total recorded uptime as value in percent
546
547Response:
548
549{
550 "server": {
551 "actions": [
552 {
553 "action": "created",
554 "date": 1556270550.746845
555 }
556 ],
557 "created_at": 1556270550.7468333,
558 "game": "dayz",
559 "gameserver": {
560 "battleye": true,
561 "gametime": [
562 "19:18"
563 ],
564 "map": "chernarusplus",
565 "max_players": 4,
566 "os": 1,
567 "players": 0,
568 "public": false,
569 "tags": [
570 "battleye",
571 "external",
572 "privHive",
573 "shard",
574 "lqs0",
575 "19:18"
576 ],
577 "vac": true,
578 "version": "1.02.151010"
579 },
580 "host": "85.131.155.68",
581 "mods": [],
582 "port": 2302,
583 "server_id": "be5c437cc3c98830abf26983e75b07c847e17886da5cafff56d3d2eda21564bd",
584 "server_name": "CFTools #1 | Testing",
585 "stats": {
586 "players": {
587 "alltime": {
588 "avg": 0.0,
589 "max": 0,
590 "min": 0
591 }
592 },
593 "server": {
594 "downtime": 0,
595 "uptime": 100.0
596 }
597 },
598 "status": true,
599 "steam": {
600 "query_port": 2303,
601 "steamid": "90125333593443331"
602 },
603 "updated_at": 1556299180
604 },
605 "status": true
606}
607
608SteamRelay
609status
610
611[GET] /v1/steamrelay/status
612
613Returns information about the current steamrelay system status, including current Valve system status.
614
615The SteamRelay scope is protected and requires authorization.
616User
617query
618
619[GET, POST] /v1/user/query
620Arguments: identity_type, identity
621Identity types: cftools_id battleye_guid bohemiainteractive_uid
622
623This endpoint accepts arguments as either GET arguments or POST body fields.
624
625status Account status
626level Account level
627platforms Individual platforms the player has played on
628flags Account flaggings
629links Available links on account
630mapped_users CFToolsIDs of potentially associated accounts
631last_seen Last visit on any CFTools webinterface
632first_seen Date of account registration
633
634Demo response:
635
636{
637 "status": true,
638 "user": {
639 "cftools_id": "5b741963c221d558724f2355",
640 "status": "staff",
641 "platforms": [
642 "omega"
643 ],
644 "flags": [
645 "webinterface:omegax",
646 "betaprogram"
647 ],
648 "links": [
649 "battleye",
650 "discord",
651 "bohemiainteractive",
652 "steam",
653 "twitch",
654 "email"
655 ],
656 "level": "vip",
657 "mapped_users": [],
658 "first_seen": 1534335331.58888,
659 "last_seen": 1552757756.94353
660 }
661}
662
663platformdata
664
665[GET] /v1/user/<cftools_id>/platformdata
666Arguments: platform
667Platforms: omega phi delta zeta
668
669aliases Last 5 aliases used
670server_datasets ServiceIDs of services the player has played on
671last_seen Timestamp of last play session
672created_at Timestamp of dataset creation (First time played on this platform)
673time_played Total time played on this platform (seconds)
674bans Platform specific bans (unused)
675adminlevel Curator level for community features (unused)
676kicks Total amount of kicks
677sessions Total amount of playsessions
678pir Latest PlayerIntegrityRating
679
680Demo response:
681
682{
683 "status": true,
684 "omega": {
685 "aliases": [
686 "Philipp",
687 "\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd\\ufffd ",
688 "philipp"
689 ],
690 "server_datasets": [
691 "5b74211ac221d55ecb1ddaea"
692 ],
693 "last_seen": 1551301234.82134,
694 "created_at": 1534342288.351827,
695 "time_played": 278564.56883335114,
696 "bans": {},
697 "adminlevel": "player",
698 "kicks": 55,
699 "sessions": 446,
700 "pir": 100.0
701 }
702}
703
704Examples
705PHP (cURL)
706
707$plain_secret = ''; // The key you receive when registering your api application
708$client_id = ''; // Replace this with the client_id stated in your application dashboard
709$user_agent = ''; // Replace this with the user agent stated in your application dashboard
710
711$hashed_secret = hash('sha256', $plain_secret);
712
713$token_url = 'https://cfbackend.de/auth/login';
714
715$data = array('secret' => $hashed_secret);
716$request = curl_init($token_url);
717curl_setopt_array($request, array(
718 CURLOPT_POST => TRUE,
719 CURLOPT_RETURNTRANSFER => TRUE,
720 CURLOPT_HTTPHEADER => array(
721 'Client-ID: '.$client_id,
722 'Content-Type: application/json'
723 ),
724 CURLOPT_POSTFIELDS => json_encode($data)
725));
726
727$response = curl_exec($request);
728$response_data = json_decode($response, TRUE);
729if(!$response_data['status']) {
730 die('Failed to obtain token: '.$response_data['error'].' ('.$response_data['error2'].')');
731}
732
733$access_token = $response_data['access_token'];
734print_r('Successfully obtained access_token');
735
736
737$request = curl_init('https://cfbackend.de/v1/servers/85.131.155.68/ataddress');
738curl_setopt_array($request, array(
739 CURLOPT_RETURNTRANSFER => TRUE,
740 CURLOPT_HTTPHEADER => array(
741 'Client-ID: '.$client_id,
742 'Authorization: Bearer '.$access_token
743 )
744));
745
746$response = curl_exec($request);
747$response_data = json_decode($response, TRUE);
748print_r($response_data);
749
750Python 3 (requests)
751
752import requests, hashlib
753
754USER_AGENT = '' # Replace this with the user agent stated in your application dashboard
755CLIENT_ID = '' # Replace this with the client_id stated in your application dashboard
756PLAIN_SECRET = '' # The key you receive when registering your api application
757
758HASHED_SECRET = hashlib.sha256(PLAIN_SECRET.encode('utf-8')).hexdigest()
759
760headers = {
761 'User-Agent': USER_AGENT,
762 'Client-ID': CLIENT_ID
763}
764
765payload = {
766 'secret': HASHED_SECRET
767}
768
769request = requests.post('https://cfbackend.de/auth/login', headers=headers, json=payload)
770if request.status_code != 200:
771 print('[!] Failed to log-in: {}'.format(request.json()))
772 sys.exit(1)
773
774headers.update({
775 'Authorization': 'Bearer {}'.format(request.json().get('access_token'))
776})
777
778request = requests.get('https://cfbackend.de/v1/servers/85.131.155.68/ataddress', headers=headers)
779print(request.json())