Walker Formulation Academy for developers API reference Error catalog OpenAPI
Sections

Account

Methods in this section: 4. All methods

MethodPathDescriptionScopesStatus
GET/meWho am I—Available
PUT/me/encryption-keyPublic key for the JWE formatwebhooks:manageAvailable
GET/walletWallet and exchange state—Available
GET/operations/{id}Get an operation—Available
GET /me Available

#Who am I

Returns the tenant, the integration, the key with its effective scopes, the rate limits and the wallet state. No scope is required: a valid key is enough. Handy for a connectivity check and for picking the cell.

Scopes
none required, a valid key is enough
Rate limit
read
Idempotency
not required
Successful response
200 The key and account description.

Response body

FieldTypeDescription
tenantobject
required
The tenant that owns the key.
tenant.idstring
required
tenant.namestring
required
cellstring
required
Platform cell: ru, en or id.
Values: ru en id
base_urlstring
required
Base URL of this cell API.
integrationobject
required
The integration (service account) that owns the key.
integration.idstring
required
integration.namestring
required
channel_idstring
required, may be null
The integration "api" channel; null — the channel is not created yet.
keyobject
required
key.key_idstring
required
Public key id (not a secret).
key.modestring
required

Values: live test
key.scopesarray<string>
required
Effective scopes: integration scopes ∩ the owner current permissions ∩ the licence.
Values: conversations:read conversations:write ai_seller:invoke leads:read leads:write leads:score analytics:read analytics:write dashboards:read articles:read articles:write articles:generate strategist:read strategist:write strategist:chat webhooks:manage channels:read channels:write cards:read cards:write
key.expires_atstring
required
Key expiry, ISO 8601 UTC.
key.ip_allowlistarray<string>
required, may be null
Allowed addresses and networks (CIDR); null — any address.
limitsobject
required
Request rate and paid-operation limits.
limits.read_per_mininteger
required
limits.write_per_mininteger
required
limits.paid_per_mininteger
required
limits.paid_concurrencyinteger
required
Concurrent paid AI operations per integration; beyond it — 429 concurrency_limit.
limits.max_operation_costMoney
required, may be null
The per-operation cost cap in the wallet currency (a higher estimate — 402 spend_limit_reached); null — could not be read.
walletobject
required
The tenant wallet (AI operations).
wallet.balanceMoney
required, may be null
The wallet balance in roubles; null — the state is unknown or the tenant is not billed.
wallet.statestring
required
ok — fine; low — running low; negative — the balance is below zero; blocked — the wallet is blocked; unknown — the state could not be obtained. Details: GET /wallet.
Values: ok low negative blocked unknown
wallet.exchangestring
required
suspended for negative and blocked: every route except /me and /wallet answers 402 wallet_suspended.
Values: active suspended
wallet.topup_urlstring
required
The dashboard address where the wallet is topped up.
wallet.daily_spendobject
required, may be null
The integration daily spend; null — could not be computed.
wallet.daily_spend.limitMoney
required, may be null
The integration daily spend limit; null — not set.
wallet.daily_spend.usedMoney
required
Charged for the integration paid operations since the start of the cell local day.
crm_modestring
required
The tenant CRM mode: "internal" (our CRM) or an external system.
pii_encryptionPiiEncryption
optional, may be null
EN and ID cells only: the JWE format of personal-data fields; null — the setting could not be read. Absent on the RU cell.

Examples

Request
curl -X GET 'https://wfacademy.id/api/public/v1/me' \
  -H 'Authorization: Bearer '"$API_KEY"
Response 200
{
  "tenant": {
    "id": "EXAMPLE_ID",
    "name": "string"
  },
  "cell": "ru",
  "base_url": "https://example.com/hooks/sapport",
  "integration": {
    "id": "EXAMPLE_ID",
    "name": "string"
  },
  "channel_id": "EXAMPLE_ID",
  "key": {
    "key_id": "EXAMPLE_ID",
    "mode": "live",
    "scopes": [
      "conversations:read"
    ],
    "expires_at": "2026-10-11T09:00:00Z",
    "ip_allowlist": [
      "string"
    ]
  },
  "limits": {
    "read_per_min": 0,
    "write_per_min": 0,
    "paid_per_min": 0,
    "paid_concurrency": 0,
    "max_operation_cost": {
      "amount": null,
      "currency": null
    }
  },
  "wallet": {
    "balance": {
      "amount": null,
      "currency": null
    },
    "state": "ok",
    "exchange": "active",
    "topup_url": "https://example.com/hooks/sapport",
    "daily_spend": {
      "limit": null,
      "used": null
    }
  },
  "crm_mode": "string",
  "pii_encryption": {
    "mode": "off",
    "key": null,
    "previous_key": null,
    "accepted": null
  }
}
Error example
{
  "type": "https://wfacademy.id/developers/errors#invalid_api_key",
  "title": "Invalid API key",
  "status": 401,
  "code": "invalid_api_key",
  "detail": "EXAMPLE",
  "request_id": "req_EXAMPLE"
}

Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.

Possible errors

invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited service_unavailable internal_error

PUT /me/encryption-key Available

#Public key for the JWE format

EN and ID cells only; 404 on RU. Registers or replaces the recipient public key (JWK) used to build personal-data field values in JWE format (RFC 7516). You create the key pair and keep the private key; private JWK members are rejected. EN: ECDH-ES+A256KW (P-256, P-384, X25519) or RSA-OAEP-256 (2048 bits or more). ID: ECDH-ES+A256KW (P-384, X25519) or RSA-OAEP-256 / RSA-OAEP-384 (3072 bits or more). enc is A256GCM. The same key again — changed: false. A new key applies at once; the previous one can still be requested with the Encryption-Key-Id header for 7 days. Registration turns mode off into optional; mode required is changed in the dashboard only.

Scopes
webhooks:manage
Rate limit
write
Idempotency
not required
Successful response
200 The setting after registration.

Request body The recipient public key.

FieldTypeDescription
jwkobject
required
The recipient public key (JWK) with an alg member. Private members (d, p, q, dp, dq, qi, k) are rejected.

Response body

FieldTypeDescription
modestring
required
off — personal-data fields are returned as is; optional — in JWE format when a key is registered; required — only in JWE format (no key — 409 encryption_key_required). The mode is set in the dashboard.
Values: off optional required
keyobject
required, may be null
The active recipient public key; null — none registered.
key.kidstring
required
Key id (from the JWK or the RFC 7638 thumbprint).
key.algstring
required
Key management algorithm: ECDH-ES+A256KW, RSA-OAEP-256 or RSA-OAEP-384.
key.ktystring
required

Values: EC OKP RSA
key.crvstring
required, may be null
Curve (EC/OKP); null for RSA.
key.rsa_bitsinteger
required, may be null
RSA modulus length, bits; null for EC/OKP.
key.thumbprintstring
required
Public key thumbprint (RFC 7638, SHA-256).
key.created_atstring
required
When the key was registered, ISO 8601 UTC.
previous_keyobject
required, may be null
The previous key after a change: it can still be requested with the Encryption-Key-Id header until expires_at (7 days).
previous_key.kidstring
required
Key id (from the JWK or the RFC 7638 thumbprint).
previous_key.algstring
required
Key management algorithm: ECDH-ES+A256KW, RSA-OAEP-256 or RSA-OAEP-384.
previous_key.ktystring
required

Values: EC OKP RSA
previous_key.crvstring
required, may be null
Curve (EC/OKP); null for RSA.
previous_key.rsa_bitsinteger
required, may be null
RSA modulus length, bits; null for EC/OKP.
previous_key.thumbprintstring
required
Public key thumbprint (RFC 7638, SHA-256).
previous_key.created_atstring
required
When the key was registered, ISO 8601 UTC.
previous_key.expires_atstring
required, may be null
acceptedobject
required, may be null
Which keys this cell accepts.
accepted.algarray<string>
required
accepted.crvarray<string>
required
accepted.min_rsa_bitsinteger
required
accepted.encstring
required
changedboolean
required
false — the same key was already registered.

Examples

Request
curl -X PUT 'https://wfacademy.id/api/public/v1/me/encryption-key' \
  -H 'Authorization: Bearer '"$API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "jwk": {}
}'
Response 200
{
  "mode": "off",
  "key": {
    "kid": "string",
    "alg": "string",
    "kty": "EC",
    "crv": "string",
    "rsa_bits": 0,
    "thumbprint": "string",
    "created_at": "2026-10-11T09:00:00Z"
  },
  "previous_key": {
    "kid": "string",
    "alg": "string",
    "kty": "EC",
    "crv": "string",
    "rsa_bits": 0,
    "thumbprint": "string",
    "created_at": "2026-10-11T09:00:00Z",
    "expires_at": "2026-10-11T09:00:00Z"
  },
  "accepted": {
    "alg": [
      "string"
    ],
    "crv": [
      "string"
    ],
    "min_rsa_bits": 0,
    "enc": "string"
  },
  "changed": false
}
Error example
{
  "type": "https://wfacademy.id/developers/errors#scope_missing",
  "title": "Scope is missing",
  "status": 403,
  "code": "scope_missing",
  "detail": "EXAMPLE",
  "request_id": "req_EXAMPLE"
}

Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.

Possible errors

invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing not_found bad_request validation_failed payload_too_large invalid_state

GET /wallet Available

#Wallet and exchange state

Returns the tenant wallet balance, its state (ok, low, negative, blocked, unknown), whether data exchange is suspended and the top-up address. No scope is required and it works even while exchange is suspended: this is where you see why the other routes answer 402 wallet_suspended. A balance below zero or a blocked wallet suspends exchange; after a top-up it resumes by itself within 30 seconds.

Scopes
none required, a valid key is enough
Rate limit
read
Idempotency
not required
Successful response
200 The wallet state.

Response body

FieldTypeDescription
balanceMoney
required, may be null
The wallet balance in roubles (the wallet is kept in RUB on every cell); null — the state is unknown or the tenant is not billed.
statestring
required
ok — fine; low — running low (exchange continues); negative — the balance is below zero; blocked — the wallet is blocked; unknown — the state could not be obtained.
Values: ok low negative blocked unknown
exchangestring
required
suspended for negative and blocked: every route except /me and /wallet answers 402 wallet_suspended and webhooks are postponed. With unknown it stays active: free reads proceed with the Wallet-State: unknown header, paid operations are closed (503).
Values: active suspended
topup_urlstring
required
The dashboard address where the wallet is topped up (a staff member with the top-up permission must sign in).
daily_spendobject
required, may be null
The integration daily spend: charges for its paid operations since the start of the cell local day; null — could not be computed.
daily_spend.limitMoney
required, may be null
The integration daily spend limit; null — not set.
daily_spend.usedMoney
required
Charged since the start of the cell local day.

Examples

Request
curl -X GET 'https://wfacademy.id/api/public/v1/wallet' \
  -H 'Authorization: Bearer '"$API_KEY"
Response 200
{
  "balance": {
    "amount": "123.45",
    "currency": "IDR"
  },
  "state": "ok",
  "exchange": "active",
  "topup_url": "https://example.com/hooks/sapport",
  "daily_spend": {
    "limit": null,
    "used": {
      "amount": null,
      "currency": null
    }
  }
}
Error example
{
  "type": "https://wfacademy.id/developers/errors#invalid_api_key",
  "title": "Invalid API key",
  "status": 401,
  "code": "invalid_api_key",
  "detail": "EXAMPLE",
  "request_id": "req_EXAMPLE"
}

Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.

Possible errors

invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited service_unavailable internal_error

GET /operations/{id} Available

#Get an operation

Returns an asynchronous operation created by your integration (a 202 response with the operation envelope): the queued, running, succeeded, failed or canceled state, the result resource and the cost of paid operations. The route needs no scope of its own: it requires the same scope as the request that created the operation (for example, ai_seller:invoke for an AI seller reply). An operation of another integration or tenant is a 404. Instead of frequent polling, subscribe to the operation.completed event.

Scopes
none required, a valid key is enough
Rate limit
read
Idempotency
not required
Successful response
200 The operation.

Parameters

FieldTypeDescription
idstring
required
In: path. Operation id (uuid) from the operation envelope.

Response body

FieldTypeDescription
operationOperation
required

Examples

Request
curl -X GET 'https://wfacademy.id/api/public/v1/operations/EXAMPLE_ID' \
  -H 'Authorization: Bearer '"$API_KEY"
Response 200
{
  "operation": {
    "id": "EXAMPLE_ID",
    "type": "string",
    "status": "queued",
    "created_at": "2026-10-11T09:00:00Z",
    "completed_at": "2026-10-11T09:00:00Z",
    "resource": {
      "type": "string",
      "id": "EXAMPLE_ID"
    },
    "error": {
      "code": "string",
      "message": "string"
    },
    "usage": {
      "cost": null,
      "model": null
    }
  }
}
Error example
{
  "type": "https://wfacademy.id/developers/errors#invalid_api_key",
  "title": "Invalid API key",
  "status": 401,
  "code": "invalid_api_key",
  "detail": "EXAMPLE",
  "request_id": "req_EXAMPLE"
}

Examples are illustrative: the key in them is a placeholder (EXAMPLE), field values are made up.

Possible errors

invalid_api_key wrong_cell integration_inactive tenant_inactive ip_not_allowed feature_not_in_plan rate_limited wallet_suspended service_unavailable internal_error scope_missing pii_transfer_not_allowed not_found