Cashier-initiated enrollment: create a PENDING_PROOF wallet + SMS a verification link
Initiates cashier-led customer enrollment by creating a wallet identity in the PENDING_PROOF state and sending the customer an SMS verification link. This is step 1 of the two-step signup flow; step 2 is POST /enroll/verify, where the customer proves phone ownership.
The request supplies a phone number, which is normalized to E.164 and used to find-or-create the customer’s wallet identity in the PENDING_PROOF state, scoped to (merchant_id, normalized_phone). A single-use, short-TTL signed verification link is then issued and delivered by SMS.
No money moves and no provider-customer link is created at this step. Both occur only at POST /enroll/verify once the customer proves ownership of the phone number.
The PENDING_PROOF wallet identity acts as an escrow target. Any promotional value accrued for an unverified customer (for example a top-up bonus or cashback) is held as a LOCKED promotional grant until verification flips the state and releases it.
A wallet identity is unique on (merchant_id, normalized_phone): the same phone number at a different merchant is a different customer. Wallet balances and grants are isolated per merchant in a closed loop and do not cross merchant boundaries.
This endpoint is idempotent on the Idempotency-Key header. A retry with the same key replays the original wallet identity and verification link without sending a new SMS and without resetting the resend rate-limit window.
If a feddi_session_id is supplied, the enrollment is associated with the live checkout session; otherwise the enrollment is standalone.
The verification SMS is transactional and does not require marketing consent opt-in.
Authorizations
POS terminal JWT minted by /auth/token; carries integrationId + terminal/cashier claims (server-trusted).
Headers
Partner-generated UUID; the ONE dedup key for all mutating endpoints. 24h TTL. Same key + same payload -> byte-identical replay; same key + different payload -> IDEMPOTENCY_KEY_REUSED (422).
Body
Body for POST /enroll/initiate. The cashier supplies a phone (E.164-normalized server-side) and optionally the POS provider customer-id.
Canonical request context, shared across all partner domains. merchant_id is key-enforced to a merchant the calling credential is authorized for (a platform-scoped credential acts only on its own tenants), so it is never a free-text trust field: a merchant_id outside the credential's authority is rejected rather than honored.
The customer's phone; normalized to E.164 server-side. The identity key is (merchant_id, normalized_phone).
Common request metadata shared across all Partner API domains. partner_request_id is a correlation identifier only: it appears in logs and responses for tracing but is never used as the deduplication key. Request deduplication is keyed exclusively on the Idempotency-Key header.
The POS provider's customer id; bound to the wallet identity at verify (provider-customer link), not at initiate.
Explicit program when the customer could map to several; NULL uses the integration's current assignment. Ambiguity → WALLET_PROGRAM_AMBIGUOUS.
Preferred SMS language (e.g. en, ar); defaults to the program/branch default.
"en"
Response
PENDING_PROOF proto-wallet created (or idempotent replay) and the verification SMS dispatched. No money moved, no provider-customer link yet.
The standard response envelope that every enveloped endpoint serializes through. ok is a boolean discriminator: when ok is true, the typed result is carried in data; when ok is false, a typed error object is returned instead. The meta object is uniform across the entire API surface.
The uniform response metadata block returned on every response. data_completeness_score is computed per call and reports the completeness of the returned data. decision_trace_id is present on responses that carry decision or insight output and can be used to correlate the response with its reasoning. capabilities is an additive, response-level array of hints advertising features the caller may use, and may be extended over time without notice.
Result of POST /enroll/initiate. The customer's wallet identity now exists in a PENDING_PROOF state and a verification SMS has been sent to the supplied phone number. No funds move during initiation, and the provider-customer link is not yet established. The link is created only once the verification step completes.
The typed error object returned with every non-2xx response. code is a string enum (for example WALLET_PROGRAM_AMBIGUOUS, CREDENTIAL_TYPE_UNSUPPORTED, INSUFFICIENT_FUNDS, IDEMPOTENCY_KEY_REUSED, CURRENCY_NOT_SUPPORTED), never a bare HTTP status number. Inspect code for programmatic branching, not the HTTP status. Some codes echo the valid set in details so clients can present or reconcile the accepted values: for example CREDENTIAL_TYPE_UNSUPPORTED lists the supported credential types, CURRENCY_NOT_SUPPORTED lists the supported ISO-4217 currencies, and WALLET_PROGRAM_AMBIGUOUS lists the candidate wallet_program_id values that matched the request.