Escrow Safe Trade is live: protect your next high-value deal Learn more
ProductsPayment links & checkoutM-Pesa, cards, invoices, split payoutsEscrow Safe TradeMilestone and release-based escrowWallets & P2PPersonal and business walletsChama, Lengo & DeniGroup savings, goals and IOUsBusiness toolkitAccounting, payroll, POS, ticketingBulk payments & payrollPay many people in one uploadSubscriptions & billingRecurring plans and renewalsRent, loans & donationsCollections and campaignsAll products
SolutionsMerchantsBuyersChama groupsBusiness solutionsIndustries
Pricing
DevelopersDeveloper overviewQuickstart, auth and sandboxREST APIsCheckout, invoices and requestsWebhooksSigned, real-time eventsWallet-as-a-ServiceVirtual sub-accountsDocumentationGuides and API reference
Security
CompanyAbout usCareersPartnersBlogHelp centreContact us
Log in Get started Talk to sales
Wallets & money movement

Business Ownership Transfer

Hand a business over to another Paysasa account with a PIN and email-OTP protected, two-sided handshake.

Base URLhttps://api.paysasa.com/api/v1Authx-api-keyFormatJSON

Transfer a business to another Pay account. Flow: current owner requests (wallet PIN + email OTP) → recipient accepts via emailed link → platform support approves. Chama ownership is not transferable on this path. Optional revoke of active API keys on completion.

Auth: signed-in dashboard/session only (not business API keys).

Availability: ownership transfer can be disabled for the platform. When disabled, the UI is hidden and these endpoints return 403.

UI: Business Settings → Transfer ownership. Accept page: /dashboard/invitations/ownership?token=…

Statuses: pending_acceptance → pending_admin → completed (or cancelled / rejected / expired). Final approval is handled by platform support, not via the merchant API.

Common errors: 403 wrong email / feature off / invalid PIN or OTP; 409 transfer already open; 429 too many OTP attempts.

GET/businesses/:id/ownership-transfer#

Owner only. Returns { enabled, transfer }.

POST/businesses/:id/ownership-transfer#

action: "send_otp" with pin, or create request with toEmail, pin, otp, optional revokeApiKeys (default true).

DELETE/businesses/:id/ownership-transfer#

Body/query transferId. Cancels open request and rotates the accept token.

GET/POST/ownership-transfers/accept

Preview (?token=) or accept with JSON body containing token. Must be signed in as the invited email.

JavaScript
// 1) Send OTP (requires wallet PIN)
await fetch("https://api.paysasa.com/api/v1/businesses/biz_xxx/ownership-transfer", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ action: "send_otp", pin: "1234" }),
});

// 2) Create transfer request
const res = await fetch("https://api.paysasa.com/api/v1/businesses/biz_xxx/ownership-transfer", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    toEmail: "[email protected]",
    pin: "1234",
    otp: "654321",
    revokeApiKeys: true,
  }),
});
const { transfer, accept_url, mail_sent } = await res.json();
JavaScript
// Recipient (signed in as invited email)
const preview = await fetch(
  "https://api.paysasa.com/api/v1/ownership-transfers/accept?token=" + encodeURIComponent(token)
).then((r) => r.json());

const accepted = await fetch("https://api.paysasa.com/api/v1/ownership-transfers/accept", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ token }),
}).then((r) => r.json());
// status becomes pending_admin until an admin approves