Localization choices
Read country, currency, language and IP-location information for display or selection. These guest-readable actions have separate shapes and limits; location suggestions do not establish residence, currency conversion or tax jurisdiction.
Unprefixed guest-readable operations
| Task | Operation |
|---|---|
| Read country choices | Countries |
| Read IP-location suggestion | Geoinfo |
| Read configured currency labels | Currency |
| List languages | Languages |
| Read one language | Language detail |
Admin-prefixed registrations with guest-readable actions
The prefix does not add an admin requirement. Supplied credentials can resolve differently on the admin path; the examples use guest reads without credentials.
| Task | Operation |
|---|---|
| Read the same global currency labels | Admin-prefixed currency |
| Read countries/grouped text with the same conditional scope | Admin-prefixed countries |
Example clients and synthetic values follow response conventions.
Shared read context
These localization reads and the service pricing-plan list allow guest access and have no required member/resource guard. Optional resource/credentials can affect shared initialization or an operation’s explicitly described behavior. These reads do not create member, payment-source or token records. Each operation states its own collection scope, lookup inputs and external/cache effects.
Read country choices
GET /api/v1/countries
Read configured country/state records, or a conditional collection of country text from users. No pagination, save or location-precision guarantee.
Before you call
Guest ACL permits this action; it has no required member/resource guard. Header resource is optional and can select grouped behavior. Without a resource it reads country records. With a resource, real=true or use_group_users_country enables grouping of all users’ country values, with no resource/user membership filter. That output can expose country text collected across resources; use it only when this is intended.
Default selection uses optional server GeoIP lookup of resolved request IP, falling back to US on unknown/unavailable result. IP resolver allows existing admin context to override ip via JSON/query; otherwise takes the last entry of plugin-forwarded header, then forwarded-for, then remote address. It is not a physical-location or trusted-client provenance guarantee.
Request
Bodyless; examples omit resource and use country-record branch.
| Name | Location | Type / requirement | Meaning |
|---|---|---|---|
| resource | header | optional public key | Enables resource settings/grouped-country option; no member token needed for guest read. |
| real | query | optional Boolean-filter value, default false | With valid resource, request grouped user country text; resource setting can select it even when real is false/omitted. |
| ip | query / JSON | optional trimmed string; admin resolver only | Admin override for selection suggestion, not an ordinary guest filter. |
Result
HTTP 200 items array; empty [] possible. Country-record branch orders sort DESC, title ASC; grouped branch has no explicit order.
| Field | Type / presence | Meaning |
|---|---|---|
| items[].id | stored integer; country branch | Local country ID. |
| items[].code | stored string / null | Country code; grouped branch always null. No complete ISO coverage promised. |
| items[].title | stored string; country branch; string grouped | Country title, or ucfirst stored user country; falsey country becomes Country not set. |
| items[].sort | stored integer; country branch | Configured ordering priority. |
| items[].selected | boolean; country branch | Code equals GeoIP result or US fallback; multiple/missing matches possible. |
| items[].states | array; country branch | Raw state rows where county_id equals country id. Every row has declared stored id (integer), code/title (string), county_id (integer); no explicit casts/null normalization. No state order specified. |
Example: Read choices without grouped user data
Read the configured collection for a form. This excerpt shows a US fallback/suggestion and one state row; the source does not establish that every country has states.
curl "${WALLKIT_API_BASE}/api/v1/countries"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/countries`);
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/countries", method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
Synthetic HTTP 200 excerpt:
{
"items": [
{
"id": 1,
"code": "US",
"title": "United States",
"sort": 1,
"selected": true,
"states": [
{
"id": 10,
"code": "CA",
"title": "California",
"county_id": 1
}
]
}
]
}
Consequential alternate
With a valid resource and real=true or grouped setting, HTTP 200 excerpt becomes:
{"items":[{"code":null,"title":"Country not set"},{"code":null,"title":"France"}]}
This branch omits id/sort/selected/states and is global user-country text. Do not require country codes from it or reinterpret text as verified geography.
Recovery
| Status | Code / shape | Cause | Next action |
|---|---|---|---|
| 200 | items:[] | No country/group rows collected. | Allow an empty choice list and ask integration owner to inspect configured data. |
| Shared failure | No dedicated action error catch | Country/state/group query fails. | Inspect selected settings/data; no stable action-specific error code promised. |
Applicable shared context errors use credential guidance.
Next task
Choose the returned display option appropriate for the form. See In-depth integration tasks for the separate pricing/file jobs; no country choice grants identity or content access.
Read an IP location suggestion
GET /api/v1/geoinfo
Read approximate country/state/city information for a supplied IP or request-resolved IP. This can perform external lookup and cache writes; it is not proof of residence or tax location.
Before you call
Guest access follows the shared read context.
Any caller can supply query ip (string filter, no IP-format validation); falsey/omitted uses the request IP resolver. The resolver’s forwarded/admin override behavior is described under countries. The GeoIP service initializes with resolved request IP as well, so supplied-query lookup may also cause a lookup of the request IP. Cache miss sends host IP to tools.keycdn.com geo lookup; response is logged and cached. Exceptions can fall back to installed GeoIP data; failures/unknown fields return null where getters lack data. No guarantee of one provider call, fresh data, lookup privacy or accuracy.
Request
Bodyless.
| Name | Location | Type / requirement | Meaning |
|---|---|---|---|
| ip | query | optional string; falsey falls back | Supplied lookup target, not verified client IP or precise physical location. |
Result
HTTP 200 data object, no items/paginator.
| Field | Type / presence | Meaning |
|---|---|---|
| data.ip | string / null | Supplied or resolved IP value. |
| data.country | string / null | country_name from retained provider/fallback lookup. |
| data.country_code | string / null | Country-code suggestion, no exhaustive standard guarantee. |
| data.state | string / null | region_name getter. External mapper does not retain region_name, so that external branch yields null; fallback data may differ. |
| data.city | string / null | Retained city suggestion; unknown can be null. |
Example: Handle an unknown documentation IP
The documentation IP is synthetic. This unknown-result excerpt teaches the null branch rather than suggesting an actual lookup was performed.
curl "${WALLKIT_API_BASE}/api/v1/geoinfo?ip=192.0.2.1"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/geoinfo?ip=192.0.2.1`);
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/geoinfo?ip=192.0.2.1", method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
Synthetic HTTP 200 excerpt:
{
"data": {
"ip": "192.0.2.1",
"country": null,
"country_code": null,
"state": null,
"city": null
}
}
Consequential alternate
A supplied IP may return non-null country/city suggestions while state remains null. A fallback result can differ; never fill unknown fields with assumed geography or use this result as an access decision.
Recovery
| Status | Code / shape | Cause | Next action |
|---|---|---|---|
| 200 | null location fields | Unknown/unavailable lookup or mapper omits field. | Let the user choose their own location; do not fabricate a jurisdiction. |
| Shared failure | No handler-specific catch/envelope | Service/cache/fallback failure escapes. | Handle missing lookup and ask integration owner to inspect external lookup/configuration. |
Next task
Use country choices for a form independently of lookup accuracy. Selected IP information does not establish currency conversion or payment tax rules.
Read configured currency labels
GET /api/v1/currency
Read available labels for display/selection; this does not convert money or guarantee a selected provider accepts a currency.
Before you call
Guest access follows the shared read context.
Request
Bodyless; no supported pagination/filter/mode/currency query. Reads global configured currencies, not resource/member-specific selection.
Result
HTTP 200 uses the following currency-label projection. There is no currency model/detail, exchange rate, precision, symbol, paginator or active filter. Config order is preserved; no complete ISO coverage promised.
| Field | Type / presence | Meaning |
|---|---|---|
| items | array, present when at least one configured value is collected | Currency-label collection; omitted when the configured collection is empty because no setItem call occurs. |
| items[].title | configured string, present in every collected item | Configured currency label, such as USD; no exchange-rate or monetary-unit meaning. |
Example: Read USD and EUR choices
Use configured labels as choices; this excerpt omits remaining configured values.
curl "${WALLKIT_API_BASE}/api/v1/currency"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/currency`);
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/currency", method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
Synthetic HTTP 200 excerpt:
{
"items": [
{
"title": "USD"
},
{
"title": "EUR"
}
]
}
Consequential alternate
An empty configured collection can omit items rather than return []. Treat absence as no collected labels, not a conversion result. Configuration access errors have no dedicated handler catch.
Recovery
| Status | Code / shape | Cause | Next action |
|---|---|---|---|
| Shared failure | No action-specific code | Currency configuration unavailable. | Ask integration owner to inspect global currencies and handle a missing collection. |
Next task
Use the selected label only in a compatible configured flow; checkout calculation establishes its own currency constraints.
Language record
Both list and detail select these fields; no explicit response casts/null normalization.
| Field | Type / presence | Meaning |
|---|---|---|
| id | stored integer | Local language ID, not an external locale identifier. |
| slug, title, description | stored string / possibly null | Configured language key, display title and description. No complete locale coverage promised. |
| is_default, active | stored flags (string annotations) | Configuration flags; list does not automatically restrict either. |
| sort | stored integer | Configured priority field; default list ordering uses id instead. |
| created_at, updated_at | stored timestamp strings | Record times; format/timezone not established here. |
List language records
GET /api/v1/languages
Read paginated configured languages. Inactive/non-default records are included unless your filter excludes them.
Before you call
Guest access follows the shared read context.
Request
Bodyless.
| Name | Location | Type / requirement | Meaning |
|---|---|---|---|
| page | query | optional; recommend integer 1 explicitly | Raw request value is cast to integer, without the int filter used by limit. No strict integer validation or explicit page default is supplied. |
| limit | query | optional integer input, default 10 | int-filtered then cast to integer for page size; no strict validation or handler upper bound. |
| by | query | optional string, default id | Ordering field passed directly to builder; use known language field. |
| sort | query | optional string, default DESC | Ordering direction passed directly; use ASC or DESC. |
| filter | query | optional bracket map / JSON string | Criteria on Languages model fields; text substring, numeric/Boolean criteria as recognized by metadata. Example minimal request uses no filter. Filters do not validate arbitrary ordering expressions. |
Result
HTTP 200 items array of language records, plus paginator. Empty items [] is explicitly returned when no rows match. Default ordering id DESC; no resource scope/active restriction.
Example: Read the first language page
Read up to ten records and use their local IDs for detail. This excerpt omits other selected language fields.
curl "${WALLKIT_API_BASE}/api/v1/languages?page=1&limit=10"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/languages?page=1&limit=10`);
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/languages?page=1&limit=10", method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
Synthetic HTTP 200 excerpt:
{
"items": [
{
"id": 10,
"slug": "en",
"title": "English"
}
],
"paginator": {
"current_page": 1,
"page": 1,
"total_pages": 1,
"total_items": 1,
"limit": 10
}
}
Consequential alternate
HTTP 200 items:[] with paginator means no matching records. An invalid filter can produce 409 invalid_field/filter/filter_date depending on the validation field; arbitrary ordering failures use invalid_data.
Recovery
| Status | Code / shape | Cause | Next action |
|---|---|---|---|
| 409 | invalid_<field> / invalid_filter / invalid_filter_date | Criteria validation fails. | Check known Languages fields and correct filter value/date; simplify to unfiltered request. |
| 409 | invalid_data | Query/paginator/detail projection fails. | Use known ordering fields/direction and inspect configured language records. |
Next task
Read a selected language with its local id, not slug.
Read one language record
GET /api/v1/languages/{id}
Read a configured language by its sanitized local numeric ID, without resource/active restriction.
Before you call
Guest access follows the shared read context.
Request
Bodyless; id path required, integer-sanitized. Registered path is not digit-restricted; use the local integer from list. No slug lookup/filter/pagination.
Result
HTTP 200 top-level language record, not items/data wrapper.
Example: Read language 10
Read the language ID returned by the list. This excerpt shows its configured display identity, not a locale validation guarantee.
curl "${WALLKIT_API_BASE}/api/v1/languages/10"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/languages/10`);
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/languages/10", method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
Synthetic HTTP 200 excerpt:
{
"id": 10,
"slug": "en",
"title": "English"
}
Consequential alternate
Unknown sanitized ID returns HTTP 404 JSON excerpt:
{"error":"language_not_found","error_description":"Language not found"}
An inactive record can still be returned; do not infer availability from successful lookup alone.
Recovery
| Status | Code / shape | Cause | Next action |
|---|---|---|---|
| 404 | language_not_found | No record matches sanitized local ID. | Refresh list and use a returned id. |
| 409 | invalid_data | Retrieval/projection failure. | Inspect configured record; do not substitute slug in this ID route. |
Next task
Use active/default flags and your integration’s selection rules. Identity language has its own resource-language association; this lookup does not create one.
Read currency labels through the admin-prefixed route
GET /api/v1/admin/currency
Read the same global configured labels as the unprefixed currency action.
Before you call
The admin-prefixed registration targets the same api controller/action as its unprefixed counterpart, with guest ACL and no required user/resource guard. No admin credential is required solely because of this prefix. If credentials are supplied, shared admin-path session resolution can differ; guest examples omit them. The collection is not restricted to an admin account.
Request
Bodyless; no supported pagination/filter/mode/currency query. Reads global configured currencies, not resource/member-specific selection.
Result
HTTP 200 uses the exact currency-label collection, including conditional items omission. Global configuration order is preserved; no currency conversion or paginator is returned.
Example: Read labels without admin credentials
The registered admin-prefixed path still permits this guest read. The excerpt shows labels, not admin-specific currency data.
curl "${WALLKIT_API_BASE}/api/v1/admin/currency"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/admin/currency`);
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/admin/currency", method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
Synthetic HTTP 200 excerpt:
{
"items": [
{
"title": "USD"
},
{
"title": "EUR"
}
]
}
Consequential alternate
An empty configured collection can omit items rather than return []. Treat absence as no collected labels, not a conversion result. Configuration access errors have no dedicated handler catch.
Recovery
| Status | Code / shape | Cause | Next action |
|---|---|---|---|
| Shared failure | No action-specific code | Currency configuration unavailable. | Ask integration owner to inspect global currencies and handle a missing collection. |
Next task
Use unprefixed currency read when its route suits your integration; neither route provides exchange rates.
Read countries through the admin-prefixed route
GET /api/v1/admin/countries
Read country/state choices or conditional global grouped country text using the same action as the unprefixed route.
Before you call
The admin-prefixed registration targets the same api controller/action as its unprefixed counterpart, with guest ACL and no required user/resource guard. No admin credential is required solely because of this prefix. If credentials are supplied, shared admin-path session resolution can differ; guest examples omit them. The collection is not restricted to an admin account.
Optional valid resource and real=true/use_group_users_country can select the global user-country branch, with the same privacy/scope limits. Existing admin credentials can affect IP resolver override; omission in this example uses default request-resolution/fallback.
Request
Bodyless; optional resource header, real query Boolean-filter flag and admin-only resolver ip override follow the countries request contract. No member/resource guard or extra admin-account filter.
Result
HTTP 200 items with the exact country/grouped projection. No paginator. Country sort DESC/title ASC; grouped order unspecified.
Example: Read the guest country-record branch
With no resource header, this reads configured country records. The excerpt omits other countries/states fields.
curl "${WALLKIT_API_BASE}/api/v1/admin/countries"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/admin/countries`);
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/admin/countries", method="GET")
try:
with urlopen(request) as response:
print(response.status, json.load(response))
except HTTPError as error:
print(error.code, json.load(error))
Synthetic HTTP 200 excerpt:
{
"items": [
{
"id": 1,
"code": "US",
"title": "United States",
"selected": true,
"states": []
}
]
}
Consequential alternate
With valid resource and grouped selection, output instead contains code:null/title strings and omits country/state/selected identifiers, as in the grouped alternate. Prefix does not add ownership/resource filtering.
Recovery
| Status | Code / shape | Cause | Next action |
|---|---|---|---|
| 200 | items:[] or grouped projection | No rows, or grouped configuration selected. | Handle empty collection and the correct conditional shape; omit resource when ordinary country records are intended. |
| Shared failure | No dedicated action catch | Country/state/group query fails. | Inspect selected settings/data; no stable action-specific error code. |
Next task
Choose the route and collection shape suited to your form. In-depth integration tasks keeps localization separate from billing/account/file jobs.