Keter Bank API Reference
A REST API for the Keter Bank Minecraft economy. Build integrations, automate transactions, and add "Login with Keter" to your own sites.
https://mc.bank.jacksampson.lol/api
Error Format
All endpoints return a consistent JSON envelope. Check success before reading other fields.
All responses include a success boolean. On failure, a message or error field describes what went wrong.
{
"success": false,
"message": "Insufficient funds",
"error_code": "INSUFFICIENT_FUNDS" // where available
}| HTTP Status | Meaning |
|---|---|
| 200 | Success (check success: true) |
| 400 | Bad request — missing or invalid parameters |
| 401 | Unauthorized — wrong credentials or expired token |
| 403 | Forbidden — account inactive or insufficient permissions |
| 404 | Not found — account, card, or resource does not exist |
| 409 | Conflict — duplicate request or state mismatch |
JWT Authentication
Protected endpoints require a signed JWT passed in the Authorization header.
How it works: Call
/api/business-login to receive a token (JWT). Pass it as a Bearer token on all subsequent requests that require authentication.// Include on every protected request: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
| Token type | Issued by | Lifetime | Used for |
|---|---|---|---|
| Business JWT | /api/business-login | 2 hours | Business endpoints and registering OAuth apps |
| API Key | Business dashboard | Until revoked | Server-to-server: card charges and transfers |
| OAuth Access Token | /api/oauth/token | 1 hour | Third-party apps reading user info via OAuth |
Registration
Apply for a Keter Bank account. Once submitted, your application is reviewed by an admin.
POST
/api/request-account
Submit an account application. Requires admin approval before the account becomes active.
Applications are reviewed by an admin. Once approved, the player will be able to log in immediately.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| username | string | Required | 3–16 chars, alphanumeric and underscores only |
| minecraft_uuid | string | Required | Standard UUID format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) |
| password | string | Required | Minimum 6 characters |
| string | Optional | Contact email address |
Response — 201 Created
{
"success": true,
"message": "Account request submitted! Please wait for admin approval."
}Cards
Process card payments as a business merchant.
POST
/api/charge-card
Process a direct card charge as a business merchant. A 2.5% + $0.10 processing fee is deducted from the settlement.
Requires a valid business API key in the
X-API-Key header.Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| merchant_business_id | string | Required | Your business account ID |
| card_number | string | Required | Full 16-digit card number |
| cvv | string | Required | 3-digit CVV |
| amount | number | Required | Charge amount |
| customer_name | string | Optional | Cardholder name for records |
Response — 200 OK (always 200; check
authorized){
"success": true,
"authorized": true,
"authorization_code": "CHRG-XYZ789",
"amount": 50.00,
"merchant_fee": 1.35, // 2.5% + $0.10
"net_amount": 48.65
}
// Declined:
{
"success": true,
"authorized": false,
"decline_reason": "Insufficient funds"
}Business Banking
Open and manage business accounts, issue API keys, and process card payments on behalf of your business.
POST
/api/business-account
Open a new business bank account. Requires an initial deposit from a personal account.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| business_name | string | Required | Legal business name |
| account_type | string | Required | Business account type |
| ein | string | Required | Employer identification number |
| industry | string | Required | Business industry |
| owners | array | Required | Array of owner objects: { uuid, name, role, password } |
| initial_deposit | number | Required | Opening deposit (minimum $100) |
| funding_account_uuid | string | Optional | Personal account UUID to fund the opening deposit |
| dba_name | string | Optional | Doing-business-as name |
| description | string | Optional | Business description |
Response — 200 OK
{
"success": true,
"business_id": "biz_abc123",
"account_number": "987654321098",
"business_name": "Creeper's Craft Shop",
"initial_balance": 500.00,
"owners_count": 1
}
POST
/api/business-login
Authenticate as an owner or admin of a business account. Returns a JWT for business endpoints.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| business_id | string | Required | Business UUID or account number |
| user_uuid | string | Required | Authorized user's Minecraft UUID |
| password | string | Optional | Required if account has a password set |
Response — 200 OK
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiJ9...", // Business JWT
"business_id": "biz_abc123",
"business_name": "Creeper's Craft Shop",
"account_number": "987654321098",
"user_name": "Steve",
"role": "OWNER",
"permissions": {
"can_view": true,
"can_transact": true,
"can_manage_users": true,
"can_charge_cards": true
}
}
POST
/api/business-transfer
Transfer funds from a business account to a personal account. Authenticated via API key in the request header.
Pass your API key as X-API-Key in the request header.
Request Headers
| Header | Required | Description |
|---|---|---|
| X-API-Key | Required | Your business API key (kb_live_…) |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| to_account_number | string | Required | 12-digit recipient personal account number |
| amount | number | Required | Transfer amount |
| description | string | Optional | Memo / transfer reason |
| reference | string | Optional | Your internal reference ID |
Response — 200 OK
{
"success": true,
"message": "Transfer successful",
"transaction_id": "txn_biz_456",
"amount": 250.00,
"from_business": "Creeper's Craft Shop",
"to_account": "123456789012",
"timestamp": "2024-12-15T14:32:00Z"
}Login with Keter
An OAuth 2.0 authorization_code flow that lets your site authenticate Keter Bank users and read their account data with their consent.
Quick start: Register your app as a business → get a client_id and client_secret → redirect users to the consent page → exchange the code for a token → call userinfo.
The flow in 4 steps
1
Register your app
Call
POST /api/oauth/register with your Business JWT. You receive a client_id and client_secret — store the secret securely, it's shown once.2
Redirect the user to the consent screen
Send users to
/oauth/authorize?client_id=…&redirect_uri=…&scope=…&state=…. They log in (if not already) and approve or deny the request.3
Exchange the authorization code for a token
Keter redirects back to your
redirect_uri with ?code=…&state=…. Your server calls POST /api/oauth/token to exchange the code for an access token.4
Fetch user data
Call
GET /api/oauth/userinfo with the access token as Authorization: Bearer <token>. Receive only the scopes the user approved.Available scopes
Scope
Fields returned
Description
profile
username
Keter username
minecraft_uuid
minecraft_uuid
Player's Minecraft UUID
balance
balance
Available account balance
account_number
account_number
12-digit bank account number
POST
/api/oauth/register
Register a new "Login with Keter" app for your business. Returns a client_id and client_secret shown once.
Secret shown once. Store your
client_secret immediately — it is hashed on our end and cannot be retrieved again. If lost, delete and re-register your app.Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| app_name | string | Required | Display name shown on the consent screen (min 2 chars) |
| redirect_uris | string[] | Required | Allowed callback URLs. Must be HTTPS (localhost/127.0.0.1 exempt) |
| scopes | string[] | Required | Scopes your app needs: profile, minecraft_uuid, balance, account_number |
Example Request
{
"app_name": "My Plugin Store",
"redirect_uris": ["https://mypluginstore.com/oauth/callback"],
"scopes": ["profile", "minecraft_uuid"]
}Response — 200 OK
{
"success": true,
"client_id": "keter_a1b2c3d4e5f6a1b2c3d4e5f6",
"client_secret": "8f14e45f...", // shown ONCE — store it now
"message": "Store your client_secret now — it cannot be retrieved again."
}
GET
/api/oauth/app-info
Fetch public information about an OAuth app. Used internally by the consent screen.
Query Parameters
| Parameter | Type | Required |
|---|---|---|
| client_id | string | Required |
Response — 200 OK
{
"success": true,
"app_name": "My Plugin Store",
"business_name": "Creeper's Craft Shop",
"allowed_scopes": ["profile", "minecraft_uuid"]
}
POST
/api/oauth/authorize
Called by the consent screen after the user approves the request. Generates a short-lived authorization code.
You don't call this directly — the consent page at
/oauth/authorize handles it. The user is redirected here automatically after approving.Consent screen URL
GET /oauth/authorize
?client_id=keter_a1b2c3d4e5f6…
&redirect_uri=https://yoursite.com/callback
&scope=profile%20minecraft_uuid
&state=random_csrf_tokenRequest Body (sent by consent page)
| Field | Type | Required | Description |
|---|---|---|---|
| client_id | string | Required | Your app's client ID |
| redirect_uri | string | Required | Must exactly match a registered redirect URI |
| scope | string | Required | Space-separated scopes (subset of what was registered) |
| state | string | Optional | Random value to prevent CSRF — echoed back in the redirect |
Success — redirects to your callback
https://yoursite.com/callback?code=abc123…&state=your_state // Code expires in 10 minutes and is single-use
Denial — redirects with error
https://yoursite.com/callback?error=access_denied&state=your_state
POST
/api/oauth/token
Exchange an authorization code for an access token. Server-to-server — never expose your client_secret in the browser.
Keep your secret server-side. This endpoint should only be called from your backend. Never send
client_secret from a browser.Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| grant_type | string | Required | Must be "authorization_code" |
| code | string | Required | The authorization code from the redirect |
| client_id | string | Required | Your app's client ID |
| client_secret | string | Required | Your app's client secret |
| redirect_uri | string | Required | Must match the URI used during authorization |
Response — 200 OK
{
"access_token": "8f14e45fceea167a5a36dedd4b...",
"token_type": "Bearer",
"expires_in": 3600, // seconds
"scope": "profile minecraft_uuid"
}
GET
/api/oauth/userinfo
Return the scoped profile data for the authenticated user. Only fields covered by the granted scopes are included.
Request Headers
| Header | Required | Description |
|---|---|---|
| Authorization | Required | Bearer <access_token> |
Response — 200 OK
{
"sub": "player-uuid-here", // always present
// scope: profile
"username": "Steve",
// scope: minecraft_uuid
"minecraft_uuid": "550e8400-e29b-41d4-a716-446655440000",
// scope: balance
"balance": 1250.00,
// scope: account_number
"account_number": "123456789012"
}
API REFERENCE