Transfer requests open on the payout dashboard. Unlock here or go directly to the request queue.
Wrong password.
Transfer requests
| Code | EGP | Phone | Method | Status | ||
|---|---|---|---|---|---|---|
| No transfer requests yet. | ||||||
How it works
- Each customer gets a unique Shopify discount code
ALKA+ their customer ID (10% off, once per friend). - Friends open
/?ref=CODE. The theme applies/discount/CODEand saves a cart attribute. - Self-referral is blocked. Refunds or cancellations inside 30 days void the 100 EGP.
- After 30 days Flow adds 100 EGP cash to the referrer’s available balance. No store credit.
- Transfer requests and Mark paid live on this page (amount and phone come from the system).
Where to look
- Customers — metafields
alka.referral_code,referral_pending,referral_available,referral_requested,referral_paid,referral_count,referral_history - Discounts — titles start with
Alka referral 10%
Pay a cash transfer
- Send InstaPay or Vodafone Cash to the phone number in the table.
- Click Mark paid on that row. Do not use Shopify Admin.
Shopify Flow (required for new customers and new orders)
Admin → Flow. Create these two workflows. They run on Shopify — no extra host. Paste the mutations into Send Admin API request.
1. Customer created → create the 10% code
- Trigger: Customer created
- Action: Send Admin API request with the metafields mutation below
- Action: Send Admin API request with the discount mutation below
mutation {
metafieldsSet(metafields: [
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_code", type: "single_line_text_field", value: "ALKA{{ customer.legacyResourceId }}" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_pending", type: "number_integer", value: "0" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_available", type: "number_integer", value: "0" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_requested", type: "number_integer", value: "0" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_paid", type: "number_integer", value: "0" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_count", type: "number_integer", value: "0" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_history", type: "json", value: "[]" }
]) { userErrors { field message } }
}
mutation {
discountCodeBasicCreate(basicCodeDiscount: {
title: "Alka referral 10% — ALKA{{ customer.legacyResourceId }}"
code: "ALKA{{ customer.legacyResourceId }}"
startsAt: "2026-01-01T00:00:00Z"
customerSelection: { all: true }
customerGets: { value: { percentage: 0.1 }, items: { all: true } }
appliesOncePerCustomer: true
combinesWith: { orderDiscounts: false, productDiscounts: true, shippingDiscounts: true }
}) { userErrors { field message } }
}
2. Referral credit hold and release — fix overwrite
Codes are ALKA plus the full customer ID, no hyphen: ALKA10206270554275. Parse with ALKA-?(\d+). Write namespace alka (not referral) and integers like 100, not 100.00.
Flow can accumulate without an external webhook: Get customer data for the referrer, then Run code adds 100, then metafieldsSet writes the new totals.
- Keep your trigger, first Run code, empty-referrer condition, and
referral-holdtag - After that, add Get customer data queried by
id:and includealkametafields - Replace the hold metafield write with the increment Run code + mutation below
- Wait 30 days, then your paid / not-cancelled condition
- Re-parse the referrer, Get customer data again, then the release Run code + mutation. Do not credit store credit.
Hold increment — Run code (after Get customer data). Return numbers as strings:
export default function main(input) {
const reward = 100;
const fields = Object.fromEntries((input.customer?.metafields || []).map((m) => [m.key, m.value]));
const n = (v) => parseInt(String(v || 0), 10) || 0;
let history = [];
try { history = JSON.parse(fields.referral_history || "[]"); } catch (e) { history = []; }
if (!Array.isArray(history)) history = [];
const orderName = input.order?.name;
const seen = history.some((row) => row.order === orderName);
if (!seen) history.push({ order: orderName, status: "pending", amount: reward, at: input.order?.createdAt });
return {
pending: String(seen ? n(fields.referral_pending) : n(fields.referral_pending) + reward),
available: String(n(fields.referral_available)),
paid: String(n(fields.referral_paid)),
count: String(seen ? n(fields.referral_count) : n(fields.referral_count) + 1),
history: JSON.stringify(history)
};
}
mutation {
metafieldsSet(metafields: [
{ ownerId: "{{ referrerGid }}", namespace: "alka", key: "referral_pending", type: "number_integer", value: "{{ pending }}" },
{ ownerId: "{{ referrerGid }}", namespace: "alka", key: "referral_available", type: "number_integer", value: "{{ available }}" },
{ ownerId: "{{ referrerGid }}", namespace: "alka", key: "referral_paid", type: "number_integer", value: "{{ paid }}" },
{ ownerId: "{{ referrerGid }}", namespace: "alka", key: "referral_count", type: "number_integer", value: "{{ count }}" },
{ ownerId: "{{ referrerGid }}", namespace: "alka", key: "referral_history", type: "json", value: {{ history | json }} }
]) { userErrors { field message } }
}
Release — Run code that subtracts 100 from pending and adds 100 to available cash (no store credit):
export default function main(input) {
const reward = 100;
const fields = Object.fromEntries((input.customer?.metafields || []).map((m) => [m.key, m.value]));
const n = (v) => parseInt(String(v || 0), 10) || 0;
let history = [];
try { history = JSON.parse(fields.referral_history || "[]"); } catch (e) { history = []; }
if (!Array.isArray(history)) history = [];
const orderName = input.order?.name;
history = history.map((row) => row.order === orderName ? { ...row, status: "available" } : row);
if (!history.some((row) => row.order === orderName)) {
history.push({ order: orderName, status: "available", amount: reward, at: input.order?.createdAt });
}
return {
pending: String(Math.max(0, n(fields.referral_pending) - reward)),
available: String(n(fields.referral_available) + reward),
paid: String(n(fields.referral_paid)),
count: String(n(fields.referral_count) || history.length),
history: JSON.stringify(history)
};
}
3. Sync payout comments → customer wallet in Admin
The referrer dashboard updates as soon as you click Mark paid. Shopify Admin metafields need this Flow so referral_available, referral_requested, and referral_paid stay in sync.
- Trigger: Scheduled time — every 5 minutes
- Action: Get customer data queried by
metafield:alka.referral_count:>0, includealkametafields - Action: For each customer
- Action: Send Admin API request with the comments query below
- Action: Run code below, then the metafields mutation
{
article(id: "gid://shopify/Article/634862960803") {
comments(first: 50) { nodes { id body } }
}
}
export default function main(input) {
const fields = Object.fromEntries((input.customer?.metafields || []).map((m) => [m.key, m.value]));
const n = (v) => parseInt(String(v || 0), 10) || 0;
const customerId = String(input.customer?.legacyResourceId || "").replace(/\D/g, "");
const comments = input.article?.comments?.nodes || input.comments || [];
const paidIds = new Set();
const rows = [];
for (const comment of comments) {
const text = String(comment.body || "").replace(/<[^>]+>/g, " ").trim();
const parts = text.split("^");
const id = String(comment.id || "").split("/").pop();
if (parts[0] === "ALKA_PAID") paidIds.add(String(parts[1] || ""));
if (parts[0] === "ALKA_PAYOUT" && String(parts[2]) === customerId) {
rows.push({ id, amount: n(parts[5]) });
}
}
let requested = 0;
let paid = 0;
for (const row of rows) {
if (paidIds.has(row.id)) paid += row.amount;
else requested += row.amount;
}
const earned = n(fields.referral_available) + n(fields.referral_requested) + n(fields.referral_paid);
const nextPaid = Math.min(paid, earned);
const nextRequested = Math.min(requested, Math.max(0, earned - nextPaid));
return {
available: String(Math.max(0, earned - nextRequested - nextPaid)),
requested: String(nextRequested),
paid: String(nextPaid)
};
}
mutation {
metafieldsSet(metafields: [
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_available", type: "number_integer", value: "{{ available }}" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_requested", type: "number_integer", value: "{{ requested }}" },
{ ownerId: "{{ customer.id }}", namespace: "alka", key: "referral_paid", type: "number_integer", value: "{{ paid }}" }
]) { userErrors { field message } }
}
Notify: [email protected] · +201055332282
