Quick Links
About This API
KAL’s public API is still in beta and unstable, and parts of it may change substantially. If you have ideas, suggestions, requests, questions, or run into an issue, send Kalends [2032147] a chat on Torn or, preferably, join the KAL Discord so you will also be notified when API behavior changes.
Every authenticated endpoint accepts either Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. Both authentication methods are supported.
The main API read limit is currently 100 calls per KAL account per minute. Rate limiting will probably move to endpoint-specific, IP-based limits soonish.
The UI/format for these API docs is based on Glasnost [1844049]’s API docs.
Player Loadout Endpoint
Get Player Loadout Endpoint
Returns the latest saved KAL loadout for a Torn player. Use cursor to retrieve older distinct loadouts.
Endpoint
GET /user/{id}/loadout
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
id |
integer | Torn player ID. | 2032147 |
Optional Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
cursor |
string | pagination.next_cursor from an earlier response for the same player. |
null |
Example Request
curl "https://api.kalends.dev/user/2032147/loadout" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY"
Example Response
{
"user_id": 2032147,
"name": "Kalends",
"observed_at": 1786331700,
"equipment": [
{
"id": 398,
"item_ref": "kAbCdEfGhIjK",
"name": "SIG 552",
"type": "Weapon",
"sub_type": "Rifle",
"stats": {
"damage": 77.19,
"accuracy": 56.26,
"armor": null,
"quality": 41.72
},
"bonuses": [
{
"id": 81,
"title": "Warlord",
"description": "24% increased respect upon final hit",
"value": 24,
"rarity": "red"
}
],
"rarity": "orange",
"slot": 1,
"slot_name": "primary",
"ammo": {
"id": 5,
"category_id": 4,
"type": "Tracer"
},
"mods": [
{
"id": 5,
"name": "1mW Laser",
"description": "+2% critical hit rate"
}
],
"effect": null,
"blocked_effects": []
}
],
"pagination": {
"next_cursor": "CURSOR_VALUE"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
user_id |
integer | Torn player ID. |
name |
string|null | Stored player name. |
observed_at |
integer | Unix timestamp when KAL observed this loadout. |
equipment |
array | Equipped items. Empty slots are omitted. |
equipment[].id |
integer | Torn base item ID. |
equipment[].item_ref |
string|null | KAL identifier for the exact item instance when applicable. |
equipment[].stats |
object|null | Exact damage, accuracy, armor, and quality values when known. |
equipment[].bonuses |
array | Observed Torn bonus IDs and values with descriptive metadata. |
equipment[].rarity |
string|null | Ranked-item rarity when applicable. |
equipment[].slot |
integer | Positive Torn equipment slot number. |
equipment[].slot_name |
string|null | Human-readable Torn equipment slot name when KAL recognizes the slot. |
equipment[].ammo |
object|null | Captured ammo information when available. |
equipment[].mods |
array | Captured weapon mods. |
equipment[].effect |
string|null | Captured item effect when present. |
equipment[].blocked_effects |
array | Captured blocked armor effects. |
pagination.next_cursor |
string|null | Cursor for the next older distinct loadout. |
Error Codes Reference
| Code | Description | HTTP Status |
|---|---|---|
| 1 | API key is required | 401 |
| 2 | Invalid API key | 401 |
| 3 | Conflicting API credentials | 400 |
| 4 | KAL account disabled | 403 |
| 5 | Required policy or consent not accepted | 403 |
| 6 | KAL account administratively restricted | 403 |
| 11 | Invalid player ID or query value | 422 |
| 13 | No visible saved loadout or cursor resource unavailable | 404 |
| 20 | Rate limit exceeded | 429 |
Notes
- The endpoint uses stored KAL data and does not contact Torn.
- Return
pagination.next_cursorunchanged with the same player ID to retrieve the next older distinct loadout. - Invalid or unavailable cursors use the same
404response as unavailable loadout history. item_refis KAL’s public exact-item identifier. It is not the raw Torn owned-item UID.- Unknown item, bonus, mod, or slot descriptive metadata is returned as
null.
Loadout Text Endpoint
Get Human-Readable Player Loadout Endpoint
Returns the same selected loadout as plain text.
Endpoint
GET /user/{id}/loadout/text
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
id |
integer | Torn player ID. | 2032147 |
Optional Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
cursor |
string | Cursor from the JSON player-loadout endpoint. | null |
Example Request
curl "https://api.kalends.dev/user/2032147/loadout/text" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY"
Example Response
=== KAL Loadout Reveal (Kalends [2032147]) ===
Observed: 2026-08-10T03:15:00+00:00
Primary: SIG 552
damage: 77.19, accuracy: 56.26, quality: 41.72
Bonuses:
- Warlord: 24% increased respect upon final hit
Error Codes Reference
Same authentication, pagination, validation, not-found, and rate-limit errors as GET /user/{id}/loadout.
Notes
- Content type is
text/plain; charset=utf-8. - Exact text formatting may change; use the JSON endpoint for machine-readable integrations.
Faction Loadouts Endpoint
Get Faction Loadouts Endpoint
Returns KAL’s stored faction roster with each member’s latest visible saved loadout.
Endpoint
GET /faction/{id}/loadouts
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
id |
integer | Torn faction ID. | 7835 |
Example Request
curl "https://api.kalends.dev/faction/7835/loadouts" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY"
Example Response
{
"faction_id": 7835,
"name": "Example faction",
"tag": "KAL",
"members_observed_at": 1786331700,
"members": [
{
"user_id": 2032147,
"name": "Kalends",
"loadout": {
"observed_at": 1786331700,
"equipment": []
}
},
{
"user_id": 1234567,
"name": "Example player",
"loadout": null
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
faction_id |
integer | Torn faction ID. |
name |
string|null | Stored faction name. |
tag |
string|null | Stored faction tag. |
members_observed_at |
integer|null | Unix timestamp when KAL last refreshed the stored faction roster. |
members |
array | Stored faction members. |
members[].user_id |
integer | Torn player ID. |
members[].name |
string|null | Stored player name. |
members[].loadout |
object|null | Latest visible loadout, or null when KAL has none available. |
Error Codes Reference
| Code | Description | HTTP Status |
|---|---|---|
| 1 | API key is required | 401 |
| 2 | Invalid API key | 401 |
| 4 | KAL account disabled | 403 |
| 5 | Required policy or consent not accepted | 403 |
| 6 | KAL account administratively restricted | 403 |
| 11 | Invalid faction ID | 422 |
| 13 | No stored faction data available | 404 |
| 20 | Rate limit exceeded | 429 |
Notes
- The endpoint uses KAL’s stored roster and does not perform a live Torn faction refresh.
loadout: nullmeans the member is known but KAL has no visible saved loadout to return.
Combat Specials Endpoint
Get Player Combat Specials Endpoint
Returns combat-related company/job specials from KAL’s stored employment data.
Endpoint
GET /user/{id}/combat-specials
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
id |
integer | Torn player ID. | 2032147 |
Example Request
curl "https://api.kalends.dev/user/2032147/combat-specials" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY"
Example Response
{
"user_id": 2032147,
"name": "Kalends",
"updated_at": 1786331700,
"company_name": "Example company",
"company_type_id": 28,
"company_rating": 9,
"specials": [
{
"name": "Combat training",
"effect": "Example combat effect",
"job_point_cost": 10,
"required_star": 7
}
]
}
Response Fields
| Field | Type | Description |
|---|---|---|
user_id |
integer | Torn player ID. |
name |
string|null | Stored player name. |
updated_at |
integer|null | Unix timestamp for the stored employment data. |
company_name |
string|null | Stored company name. |
company_type_id |
integer|null | Torn company type ID. |
company_rating |
integer|null | Stored company star rating. |
specials |
array | Combat-related specials available from the stored company type/rating. |
specials[].name |
string | Special name. |
specials[].effect |
string | Human-readable effect. |
specials[].job_point_cost |
integer | Job-point cost. |
specials[].required_star |
integer | Required company star rating. |
Error Codes Reference
| Code | Description | HTTP Status |
|---|---|---|
| 1 | API key is required | 401 |
| 2 | Invalid API key | 401 |
| 4 | KAL account disabled | 403 |
| 5 | Required policy or consent not accepted | 403 |
| 6 | KAL account administratively restricted | 403 |
| 11 | Invalid player ID | 422 |
| 13 | No stored player record available | 404 |
| 20 | Rate limit exceeded | 429 |
Notes
- The endpoint uses stored KAL data and does not contact Torn.
updated_atis the employment-data timestamp, not the player’s loadout timestamp.
Ranked Items Endpoint
Search Ranked Items Endpoint
Searches exact ranked weapon and armor instances stored by KAL.
Endpoint
GET /ranked-items
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
sort |
string | name, rarity, damage, accuracy, armor, quality, bonus1, bonus2, auction_price, or auction_ended_at. |
bonus1 |
Optional Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
category |
string | weapons or armor. |
weapons |
item_id |
integer | Exact Torn base item ID. | null |
sub_type |
string | Exact Torn item subtype, case-insensitive. | null |
slot |
string | primary, secondary, melee, body, temporary, helmet, pants, boots, or gloves. |
null |
armor_set |
string | Named armor set. | null |
rarity |
string | yellow, orange, or red. |
null |
source |
string | loadout or auction. |
null |
bonus1 |
string | Official Torn bonus ID or bonus name. Numeric values match an exact ID; names are case-insensitive. | null |
bonus1_min / bonus1_max |
number | Inclusive value range for bonus1; requires bonus1. |
null |
bonus2 |
string | Second independent Torn bonus ID/name selector. | null |
bonus2_min / bonus2_max |
number | Inclusive value range for bonus2; requires bonus2. |
null |
bonus_count |
integer | Exact bonus count: 1 or 2. |
null |
damage_min / damage_max |
number | Inclusive damage range; weapons only. | null |
accuracy_min / accuracy_max |
number | Inclusive accuracy range; weapons only. | null |
armor_min / armor_max |
number | Inclusive armor range; armor only. | null |
quality_min / quality_max |
number | Inclusive quality range. | null |
auction_price_min / auction_price_max |
integer | Inclusive latest completed-auction price range. | null |
auction_ended_after / auction_ended_before |
integer | Unix timestamp range for the latest completed auction. | null |
direction |
string | asc or desc. |
desc |
include_total |
boolean | Include the exact result count in total. |
false |
limit |
integer | Number of items to return, 1-100. | 25 |
cursor |
string | pagination.next_cursor from the previous page. |
null |
Example Request
curl --get "https://api.kalends.dev/ranked-items" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY" \
--data-urlencode "category=weapons" \
--data-urlencode "source=loadout" \
--data-urlencode "bonus1=81" \
--data-urlencode "sort=bonus1" \
--data-urlencode "direction=desc" \
--data-urlencode "limit=25"
Example Response
{
"items": [
{
"item_ref": "kAbCdEfGhIjK",
"id": 398,
"name": "SIG 552",
"type": "Weapon",
"sub_type": "Rifle",
"stats": {
"damage": 77.19,
"accuracy": 56.26,
"armor": null,
"quality": 41.72
},
"bonuses": [
{
"id": 81,
"title": "Warlord",
"description": "24% increased respect upon final hit",
"value": 24,
"rarity": "red"
}
],
"rarity": "orange",
"slot": 1,
"slot_name": "primary",
"sources": [
{
"type": "loadout",
"latest_appearance": {
"user_id": 2032147,
"name": "Kalends",
"slot": 1,
"slot_name": "primary",
"observed_at": 1786331700
}
},
{
"type": "auction",
"latest_sale": {
"listing_id": 9000000001,
"ended_at": 1786331800,
"price": 123456789,
"bids": 7,
"seller_id": 123456,
"buyer_id": 789012
}
}
]
}
],
"total": null,
"pagination": {
"next_cursor": "CATALOG_CURSOR"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
items |
array | Exact item instances matching the query. |
items[].item_ref |
string | Canonical KAL identifier for the exact item instance. |
items[].id |
integer | Torn base item ID. |
items[].stats |
object|null | Exact-instance damage, accuracy, armor, and quality. |
items[].bonuses |
array | Exact bonus IDs, values, and descriptive metadata. |
items[].rarity |
string|null | Ranked-item rarity. |
items[].slot, items[].slot_name |
integer / string|null | Positive numeric slot and readable name when KAL recognizes it. |
items[].sources |
array | Visible loadout and/or completed auction evidence summaries. |
total |
integer|null | Exact match count when include_total=true; otherwise null. |
pagination.next_cursor |
string|null | Cursor for the next page. |
Error Codes Reference
| Code | Description | HTTP Status |
|---|---|---|
| 1 | API key is required | 401 |
| 2 | Invalid API key | 401 |
| 4 | KAL account disabled | 403 |
| 5 | Required policy or consent not accepted | 403 |
| 6 | KAL account administratively restricted | 403 |
| 11 | Invalid filter, selector, range, sort combination, or cursor | 422 |
| 20 | Rate limit exceeded | 429 |
Notes
- All supplied filters are ANDed together.
- Category-incompatible filters return
422instead of being ignored. - Unknown item or bonus descriptive metadata is returned as
null. bonus1andbonus2are query labels, not physical bonus positions.sourcerequires that visible evidence source. Source-specific filters can independently require another source.- Return
pagination.next_cursorunchanged with the same filters, sort, direction, and visibility context. - Syntactically valid filters with no matches return HTTP
200withitems: []. - The endpoint uses stored KAL data and does not contact Torn.
Exact Item Endpoint
Get Exact Item Endpoint
Resolves one exact item by KAL item_ref or a positive raw Torn owned-item UID.
Endpoint
GET /items/{item}
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
item |
string | KAL item_ref (k + 11 opaque characters) or positive Torn owned-item UID. |
kAbCdEfGhIjK |
Example Request
curl "https://api.kalends.dev/items/kAbCdEfGhIjK" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY"
Example Response
{
"item_ref": "kAbCdEfGhIjK",
"id": 398,
"name": "SIG 552",
"type": "Weapon",
"sub_type": "Rifle",
"stats": {
"damage": 77.19,
"accuracy": 56.26,
"armor": null,
"quality": 41.72
},
"bonuses": [
{
"id": 81,
"title": "Warlord",
"description": "24% increased respect upon final hit",
"value": 24,
"rarity": "red"
}
],
"rarity": "orange",
"slot": 1,
"slot_name": "primary",
"sources": [
{
"type": "loadout",
"latest_appearance": {
"user_id": 2032147,
"name": "Kalends",
"slot": 1,
"slot_name": "primary",
"observed_at": 1786331700
}
}
]
}
Response Fields
Same item shape as entries returned by GET /ranked-items.
Error Codes Reference
| Code | Description | HTTP Status |
|---|---|---|
| 1 | API key is required | 401 |
| 2 | Invalid API key | 401 |
| 4 | KAL account disabled | 403 |
| 5 | Required policy or consent not accepted | 403 |
| 6 | KAL account administratively restricted | 403 |
| 11 | Invalid item identifier | 422 |
| 13 | Item unavailable | 404 |
| 20 | Rate limit exceeded | 429 |
Notes
- Responses always use
item_refas the canonical public exact-item identifier. - KAL item refs begin with
k; positive numeric identifiers are treated as caller-supplied Torn owned-item UIDs. - A raw Torn owned-item UID is lookup-only and is not echoed as the public identity.
- Unknown and not-visible item identifiers share the same
404response.
Item History Endpoint
Get Exact Item History Endpoint
Returns visible loadout appearances and completed auction sales for one exact item, newest first.
Endpoint
GET /items/{item}/history
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
item |
string | KAL item_ref (k + 11 opaque characters) or positive Torn owned-item UID. |
kAbCdEfGhIjK |
Optional Parameters
| Parameter | Type | Description | Default |
|---|---|---|---|
source |
string | loadout or auction. |
null |
limit |
integer | Number of events to return, 1-50. | 25 |
cursor |
string | pagination.next_cursor from the previous history page. |
null |
Example Request
curl "https://api.kalends.dev/items/kAbCdEfGhIjK/history?limit=25" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY"
Example Response
{
"item_ref": "kAbCdEfGhIjK",
"history": [
{
"type": "auction",
"listing_id": 9000000001,
"ended_at": 1786331800,
"price": 123456789,
"bids": 7,
"seller_id": 123456,
"buyer_id": 789012
},
{
"type": "loadout",
"user_id": 2032147,
"name": "Kalends",
"slot": 1,
"slot_name": "primary",
"observed_at": 1786331700,
"loadout_cursor": "LOADOUT_CURSOR"
}
],
"pagination": {
"next_cursor": "HISTORY_CURSOR"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
item_ref |
string | Canonical KAL exact-item identifier. |
history |
array | Reverse-chronological visible history events. |
history[].type |
string | loadout or auction. |
history[].observed_at |
integer | Loadout event timestamp. |
history[].loadout_cursor |
string|null | Cursor that can retrieve the distinct player loadout containing that sighting. |
history[].ended_at |
integer | Auction event end timestamp. |
history[].price |
integer | Final recorded auction price. |
pagination.next_cursor |
string|null | Cursor for the next older history page. |
Error Codes Reference
| Code | Description | HTTP Status |
|---|---|---|
| 1 | API key is required | 401 |
| 2 | Invalid API key | 401 |
| 4 | KAL account disabled | 403 |
| 5 | Required policy or consent not accepted | 403 |
| 6 | KAL account administratively restricted | 403 |
| 11 | Invalid item identifier, source, limit, or cursor | 422 |
| 13 | Item unavailable | 404 |
| 20 | Rate limit exceeded | 429 |
Notes
pagination.next_cursorpaginates the item-history stream.- A loadout event’s
loadout_cursoris different: pass it toGET /user/{user_id}/loadout?cursor=...to retrieve that distinct loadout. - An otherwise visible item with no matching events returns HTTP
200withhistory: []. - The endpoint uses stored KAL data and does not contact Torn.
Check Key Endpoint
Check API Key Status Endpoint
Endpoint
GET /check-key
Required Parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
key |
string | Torn API key registered with KAL. Use Authorization: ApiKey YOUR_TORN_API_KEY or ?key=YOUR_TORN_API_KEY. |
YOUR_TORN_API_KEY |
Example Request
curl "https://api.kalends.dev/check-key" \
-H "Authorization: ApiKey YOUR_TORN_API_KEY"
Example Response
{
"is_registered": true
}
Response Fields
| Field | Type | Description |
|---|---|---|
is_registered |
boolean | Whether this exact Torn API key is registered with KAL. |
Error Codes Reference
| Code | Description | HTTP Status |
|---|---|---|
| 1 | API key is required | 401 |
| 2 | API key is invalid or disabled | 401 |
| 3 | Conflicting API credentials | 400 |
| 4 | KAL account disabled | 403 |
| 6 | KAL account administratively restricted | 403 |
| 20 | Rate limit exceeded | 429 |
Notes
- This endpoint checks KAL’s stored state only. It does not contact Torn.
- This endpoint does not register an API key.
- This endpoint does not consume the main API read budget; repeated unrecognized keys are subject to separate abuse protection.
- A well-formed key that is unknown, revoked, erased, or never registered returns HTTP
200withis_registered: false.