Account requests and optional payment
Record an application request and, only when intended, submit a separate legacy Stripe payment attempt for that record. The returned account_id identifies the application request. It does not mean a member account has been created.
| Task | Operation | Access |
|---|---|---|
| Record an application | Create request | Guest; fixed deployment resource. |
| Attempt payment for an existing request | Payment attempt | Guest; no record-owner check. |
Example clients and synthetic values follow response conventions.
Request context and returned fields
Both actions permit guest access without a member token or required resource header. They replace resource context with one fixed deployment resource; sending a resource public key does not select another account-request resource. The deployment resource must exist for request-event handling. No account-owner check is added by these actions. Protect record selection in your trusted application; an account-request ID is not proof of ownership.
| Field | Type / presence | Meaning |
|---|---|---|
| account_id | stored integer; HTTP 200 | AccountRequests record ID, retained between these two calls. No member/session/entitlement is created by the response. |
| message | string; HTTP 200 | Operation-specific acknowledgement shown in its example; not proof of downstream completion or settlement. |
| error | boolean true; field-validation failure | Direct validation response, distinct from string API error codes. |
| error_fields | object; field-validation failure | Dynamic field-name → validator-message strings; messages can vary, and the last message for a repeated field wins. Create keys are first_name, last_name, company_name, job_title, email, plan, number_of_websites and conditionally stripe_token; payment keys are account_id and stripe_token. |
| error | string; handled body/record/action failure | Code described in operation recovery. |
| error_description | string; string-code error | Human explanation; no provider object is returned. |
| req_guid | string; string-code error | Request correlation value. Direct field-validation responses do not add it unless debug metadata does. |
Other optional debug metadata follows response conventions.
Record an application request
POST /api/v1/account-requests
Save submitted contact/application fields, then attempt an account_request queue event. There is no duplicate guard or idempotency key. Repeating the submission can create another record.
Before you call
Use the account-request context. The action saves an AccountRequests record with server timestamps and REMOTE_ADDR IP, then attempts a queue event carrying its ID, email, plan and fixed resource ID. Queue transmission failure can be swallowed; an acknowledgement does not prove delivery or downstream processing. A later failure can leave the saved record in place.
No active email call or account/user provisioning occurs in this action. An optional Stripe token is stored here, with no provider call. Plan is only a required string: there is no service-pricing-plan lookup or closed enum validation.
Request
Content-Type: application/json; truthy decoded body required. Submit an object with these fields. Presence validators run before storage sanitization; there is no explicit strict JSON-type or length validation for the required strings.
| Name | Location | Type / requirement | Meaning / constraint |
|---|---|---|---|
| first_name | JSON | required string | Contact name; string/trim sanitization when saved. |
| last_name | JSON | required string | Contact surname; string/trim sanitization when saved. |
| company_name | JSON | required string | Company label; string/trim sanitization. |
| job_title | JSON | required string | Contact role; string/trim sanitization. |
| JSON | required valid email | Trimmed for validation; email/trim/lower sanitization for storage. | |
| plan | JSON | required string | Requested label; trimmed/string sanitized, with no Pricing ID or accepted-plan lookup. pro and pro-early are recognized by the separate payment price branch. |
| number_of_websites | JSON | optional number, default 1 on omission/null | Presence and between 1–10 validation, then integer-filter storage. Supply an integer; no strict integer JSON-type validation. |
| phone_number | JSON | optional string / null | String/trim sanitization; no phone format validation. |
| terms_and_conditions | JSON | optional Boolean-filter value, default false | Stored boolean; no active required/true acceptance validation. Example supplies true explicitly. |
| stripe_token | JSON | optional supplied string | Only truthy supplied values are validated/stored; no charge here. Omit when only recording the request. |
Result
HTTP 200 JSON fields use the request-result table. account_id identifies the saved application record; message acknowledges the application path. No user/session, provider result or public record details are serialized.
Example: Keep the new request ID without implying provisioning
Submit an application for two websites without a payment token. Retain synthetic account_id 8001 as the request ID only.
curl -X POST "${WALLKIT_API_BASE}/api/v1/account-requests" \
-H "Content-Type: application/json" \
--data-raw '{"first_name": "Alex", "last_name": "Reader", "company_name": "Example Media", "job_title": "Publisher", "email": "reader@example.com", "plan": "pro-early", "number_of_websites": 2, "terms_and_conditions": true}'
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/account-requests`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({"first_name": "Alex", "last_name": "Reader", "company_name": "Example Media", "job_title": "Publisher", "email": "reader@example.com", "plan": "pro-early", "number_of_websites": 2, "terms_and_conditions": true})
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
body = {'first_name': 'Alex', 'last_name': 'Reader', 'company_name': 'Example Media', 'job_title': 'Publisher', 'email': 'reader@example.com', 'plan': 'pro-early', 'number_of_websites': 2, 'terms_and_conditions': True}
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/account-requests",
data=json.dumps(body).encode("utf-8"),
headers={"Content-Type": "application/json"}, method="POST")
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:
{
"account_id": 8001,
"message": "Thank you! Wallkit Limited Beta: Application Successful!"
}
The saved request may be available even if later processing fails; this result does not sign the person in.
Consequential alternate
If record/event-stage handling throws a caught exception, HTTP 409 excerpt (other response metadata omitted):
{
"error": "account_request_create_error",
"error_description": "Error creating account request"
}
A record may already have been saved. Do not automatically submit again; ask integration owner to reconcile the attempt.
Recovery
| HTTP status | API code / shape | Cause | Next action |
|---|---|---|---|
| 406 | incorrect_data; Body must be json format | No truthy decoded JSON body. | Send a JSON object with the required fields and correct media type. |
| 409 | error:true plus error_fields | Required fields, email or website range validation fails. | Correct the named fields; treat messages as dynamic validation text. |
| 409 | account_request_create_error | Save or subsequent caught handling error. | Reconcile existing request state before resubmitting; input validation is not the only failure point. |
Next task
Keep the request acknowledgement. Only when a payment is intended for this record, read the separate payment attempt and its duplicate/partial-write behavior first.
Attempt payment for an existing request
POST /api/v1/account-requests-payment
Create a Stripe customer and charge for an existing account-request record. The action has no already-paid guard or idempotency key: retrying can create another customer and charge.
Before you call
Use the account-request context and the account_id returned by request creation. The action checks required input presence, then selects AccountRequests directly by the supplied account_id; it has no ownership/resource check or explicit numeric validation. Supply only the intended integer record ID.
Provide an existing provider token for this deployment’s Stripe integration. The server uses its ACCOUNT_REQUST_STRIPE_PRIVATE_KEY configuration (spelling preserved); that key determines provider account/mode. This action does not select the resource’s default payment provider or payments_in_live_mode and accepts no mode flag.
It first replaces/stores stripe_token and refreshes the record. A failed token save is logged without stopping, so the refreshed token can be the previously stored value. It then creates a Stripe customer with stored email/token, calculates amount and creates a charge. Final customer/charge persistence failure is also logged without stopping. Provider writes can precede local failure; no enclosing transaction, rollback or refund guarantee. No active email/payment-event call or Purchases/Transactions/membership creation occurs here.
Request
Content-Type: application/json; truthy decoded body required.
| Name | Location | Type / requirement | Meaning / constraint |
|---|---|---|---|
| account_id | JSON | required; supply integer record ID | Presence validated, passed directly to record lookup without numeric sanitization or ownership proof. Use the account-request ID, not a user ID. |
| stripe_token | JSON | required supplied string | Presence validated then string sanitized for storage; provider source uses refreshed stored value. No local provider-token format check. |
Charge amount is 19900 multiplied by the stored number_of_websites, passed without conversion, with currency USD. pro-early, pro and every other plan label currently select the same 19900 value. The action supplies no independent amount/unit validation; this documents the provider argument, not a universal Wallkit money unit or configurable service-plan price.
Result
HTTP 200 JSON fields use the request-result table. The acknowledgement follows provider customer/charge returns and attempted persistence. The action does not inspect charge status, paid/captured or settlement. Provider customer/charge objects and amount are not exposed in the result.
Example: Interpret the payment acknowledgement for request 8001
This scenario uses the request ID from the creation example and an obvious synthetic provider-token placeholder. A source-path acknowledgement assumes provider calls return without caught exceptions; the placeholder cannot perform a payment. With two stored websites, the charge argument amount is 39800 and currency USD.
curl -X POST "${WALLKIT_API_BASE}/api/v1/account-requests-payment" \
-H "Content-Type: application/json" \
--data-raw '{"account_id": 8001, "stripe_token": "SYNTHETIC_PROVIDER_TOKEN"}'
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/account-requests-payment`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({"account_id": 8001, "stripe_token": "SYNTHETIC_PROVIDER_TOKEN"})
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError
body = {'account_id': 8001, 'stripe_token': 'SYNTHETIC_PROVIDER_TOKEN'}
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/account-requests-payment",
data=json.dumps(body).encode("utf-8"),
headers={"Content-Type": "application/json"}, method="POST")
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:
{
"account_id": 8001,
"message": "Thank you! Wallkit Early Bird: Successfully Signed Up!"
}
Do not read the literal sign-up message as account provisioning, confirmed settlement or successful local persistence.
Consequential alternate
A caught provider or subsequent handling exception produces HTTP 409 excerpt (other response metadata omitted):
{
"error": "account_request_payment_error",
"error_description": "Error payment account request"
}
Token/customer/charge effects may already exist. Do not blindly retry: another attempt can create another charge.
Recovery
| HTTP status | API code / shape | Cause | Next action |
|---|---|---|---|
| 406 | incorrect_data; Body must be json format | No truthy decoded JSON body. | Send the required JSON object with correct media type. |
| 409 | error:true plus error_fields | account_id or stripe_token missing/empty under presence validation. | Supply the intended request ID and provider token; do not substitute member credentials. |
| 404 | account_request_not_exists; Account request not found | Record lookup returns no request. | Check the ID against the saved application acknowledgement; do not create a new record automatically. |
| 409 | account_request_payment_error | Caught provider/amount/handling exception. | Ask integration owner to reconcile provider and local state before deciding on another attempt. |
| 200 | Acknowledgement despite unchecked local-save failure | Provider path returns but persistence can fail. | Do not infer durable charge state from this response; reconcile through the integration owner. |
Next task
Retain the acknowledgement and reconcile the intended payment outcome through the integration owner. Return to In-depth integration tasks for unrelated choices; this response establishes no content-access decision.