Automating Binance P2P payments isn't about replacing traders — it's about removing repetitive manual work while keeping every payment verifiable through official APIs.
If you've ever traded on Binance P2P in Kenya, you've probably repeated the same workflow hundreds of times.
A new order appears.
You open M-PESA.
You enter the recipient's phone number.
You send the payment.
You wait for confirmation.
You return to Binance.
You mark the order as paid.
Then you move on to the next order.
After doing this dozens or even hundreds of times every day, one question naturally comes up:
Can the entire payment workflow be automated without relying on browser automation or unofficial tools?
The answer is yes.
Using the Binance API together with the official Safaricom Daraja API, it is possible to build a reliable payment engine that handles almost the entire workflow automatically while still keeping the merchant in control.
Why Not Use Browser Automation?
Many automation projects begin by simulating mouse clicks, keyboard input, and browser interactions.
Although this approach may appear simple at first, it introduces several serious problems:
- UI changes can break the automation
- browser sessions can expire
- page loading times are unpredictable
- error handling becomes complicated
- scaling becomes difficult
- browser state must be continuously maintained
- payment confirmation may be unreliable
Official APIs provide a much cleaner solution.
Instead of controlling a browser, the software communicates directly with Binance and Safaricom using authenticated API requests.
This produces structured responses, predictable error codes, and a workflow that can be properly logged and monitored.
Overall Architecture
The system is divided into independent modules, each responsible for one part of the payment lifecycle.
Binance P2P
│
▼
Order Detection Engine
│
▼
Payment Processing
│
▼
Safaricom Daraja API
│
▼
M-PESA Network
│
▼
Payment Callback
│
▼
Transaction Verification
│
▼
Binance P2P Chat
│
▼
Mark Order as Paid
Each component has a single responsibility.
Instead of building one giant script, the system is separated into modules that communicate through clearly defined events and transaction states.
This makes the platform easier to:
- debug
- extend
- monitor
- test
- maintain
- adapt to other payment providers
Detecting a Binance P2P Order
The process begins when a new Binance P2P BUY order is detected.
The order detection engine collects the information required by the payment module, such as:
- order number
- fiat currency
- crypto asset
- payment amount
- counterparty details
- payment method
- order status
- available payment instructions
A simplified internal order object may look like this:
{
"orderNumber": "123456789",
"advOrderNumber": "987654321",
"tradeType": "BUY",
"asset": "USDT",
"fiat": "KES",
"price": "129.50",
"amount": "10",
"totalPrice": "1295.00",
"orderStatus": 1,
"counterPartNickName": "ExampleSeller"
}
This data is then passed to the payment engine.
The payment engine does not immediately assume that the payment should be sent. It first validates the order and checks whether the same transaction has already been processed.
Preventing Duplicate Payments
Duplicate processing is one of the most dangerous problems in payment automation.
A callback may be delivered more than once.
A worker may restart.
A network request may time out even though the payment was successfully accepted.
The same order may appear again after the application reconnects.
For that reason, every order must have a unique internal transaction record.
Before sending money, the system verifies:
Has this Binance order already been processed?
│
┌────────┴────────┐
│ │
Yes No
│ │
▼ ▼
Stop processing Create payment task
A reliable implementation should store at least:
- Binance order number
- internal payment ID
- M-PESA request ID
- transaction status
- amount
- destination
- creation timestamp
- callback timestamp
- final transaction reference
This makes payment processing idempotent.
In other words, processing the same event multiple times should not result in multiple payments.
Sending the Payment Through Daraja
For an automated Binance P2P BUY workflow, the payment engine can initiate a payout through the Safaricom Daraja API.
A simplified request lifecycle looks like this:
Create Payment Request
│
▼
Authenticate with Daraja
│
▼
Submit B2C Payment
│
▼
Receive Request Identifier
│
▼
Store Transaction as Pending
At this stage, the transaction is not yet considered completed.
The API may accept the request for processing, but that does not necessarily mean the money has already reached the recipient.
That distinction is extremely important.
Why the Callback Is More Important Than the Initial Response
One mistake I often see is treating the initial API response as confirmation that the payment was completed.
In most asynchronous payment systems, the first response only confirms that the request was received.
The final result arrives later through a callback.
Payment Request Sent
│
▼
Request Accepted
│
▼
Waiting for Callback
│
▼
Callback Received
│
▼
Payment Verified
The callback becomes the primary source of truth for the payment result.
Only after receiving and validating the callback should the system continue processing the Binance order.
This approach makes the workflow significantly more reliable than continuously polling the payment provider.
Callback Processing
When Safaricom sends the callback, the callback server must:
- accept the incoming request
- validate the request structure
- identify the corresponding internal transaction
- check whether the callback was already processed
- extract the result code
- store the M-PESA transaction details
- update the payment status
- notify the next stage of the workflow
A successful callback can move the transaction from:
PENDING
to:
COMPLETED
A failed callback may move it to:
FAILED
or:
REQUIRES_REVIEW
The exact state depends on the error and whether the payment result can be safely determined.
Example Payment States
A small state machine helps keep the workflow predictable.
NEW_ORDER
│
▼
VALIDATED
│
▼
PAYMENT_REQUESTED
│
▼
WAITING_CALLBACK
│
├───────────────┐
▼ ▼
PAYMENT_SUCCESS PAYMENT_FAILED
│
▼
BINANCE_UPDATED
│
▼
COMPLETED
This is safer than relying on a collection of unrelated Boolean variables such as:
payment_sent = True
callback_received = False
order_updated = False
A transaction should always have one clearly defined current state.
Typical Order Flow
A simplified successful workflow looks like this:
Buyer creates Binance P2P order
│
▼
Bot detects the new order
│
▼
Validate order and payment details
│
▼
Create internal transaction record
│
▼
Send B2C payment through Daraja
│
▼
Store transaction as pending
│
▼
Receive official callback
│
▼
Verify transaction result
│
▼
Send message through Binance P2P Chat
│
▼
Mark Binance order as paid
│
▼
Store final transaction information
The payment should not be considered successful until the callback confirms the final result.
Binance P2P Chat Integration
After a successful payment, the bot can send a message through Binance P2P Chat.
For example:
Payment has been sent successfully.
Please verify the payment and release the crypto.
The message may also include a payment reference when appropriate.
Payment completed successfully.
M-PESA reference: ABC123XYZ
Please verify the transaction and release the crypto.
The system should avoid sending messages before payment confirmation.
Otherwise, the seller could be notified even though the payment request later failed.
Marking the Order as Paid
After receiving a successful M-PESA callback, the system can continue with the Binance order workflow.
The exact action depends on the available Binance integration and configured safety rules.
A conservative implementation may:
- confirm the payment internally
- notify the operator
- send a Binance chat message
- require manual confirmation before marking the order as paid
A more automated implementation may mark the order as paid automatically after all verification checks pass.
The important point is that the action should occur only after a confirmed payment result.
Error Handling Matters
Real production systems must expect failures.
During development, one of the responses returned by Daraja looked like this:
{
"ResultCode": 2001,
"ResultDesc": "The initiator information is invalid."
}
At first glance, this may look like a general payment failure.
In practice, it usually indicates a problem with the configured B2C Initiator credentials, authorization, security credential, or permissions assigned to the initiator.
The payment amount or recipient may be correct, but Daraja rejects the request because the initiator information cannot be validated.
Possible causes include:
- incorrect initiator username
- invalid encrypted security credential
- sandbox credentials used in production
- production credentials used in sandbox
- B2C access not enabled for the account
- initiator not authorized for the requested command
- incorrect certificate used to generate the security credential
Detailed logs are essential for identifying which part of the request failed.
Logging the Payment Lifecycle
A useful payment log should describe each important transition.
[ORDER] New Binance P2P BUY order detected
[ORDER] Order number: 123456789
[PAYMENT] Payment task created
[DARAJA] Access token received
[DARAJA] B2C request submitted
[PAYMENT] Waiting for callback
[CALLBACK] Callback received
[CALLBACK] Transaction verified
[BINANCE] Payment confirmation message sent
[BINANCE] Order marked as paid
[ORDER] Processing completed
Errors should include enough context to reproduce the issue without exposing secrets.
[DARAJA_ERROR] ResultCode: 2001
[DARAJA_ERROR] ResultDesc: The initiator information is invalid
[DARAJA_ERROR] Environment: sandbox
[DARAJA_ERROR] CommandID: BusinessPayment
[DARAJA_ERROR] Internal transaction: PAY-123456
Sensitive information should never be written directly to logs.
Avoid logging:
- API secrets
- full access tokens
- private keys
- complete security credentials
- full customer account information
- unmasked phone numbers when not required
Retry Logic
Not every failed network request means that the payment failed.
For example, the payment request may reach Safaricom successfully while the HTTP response is lost because of a network timeout.
Blindly retrying the payment could send the money twice.
For that reason, retries must depend on the transaction state.
Safe retry examples include:
- retrying token generation
- retrying a failed callback database write
- retrying a Binance chat message
- retrying a status query
Potentially dangerous retries include:
- submitting the same B2C payment again without checking its status
- creating a second payment for the same Binance order
- retrying after an unknown timeout without transaction reconciliation
The system must distinguish between:
REQUEST_FAILED
and:
REQUEST_STATUS_UNKNOWN
An unknown result should be investigated before another payment is initiated.
Callback Security
A callback endpoint is publicly accessible, so it must not trust arbitrary incoming requests.
At minimum, the callback handler should verify:
- expected request structure
- known transaction identifier
- expected amount
- expected account or recipient
- callback processing state
- duplicate callback status
It is also useful to restrict access where supported and store the raw callback payload for auditing.
The system should never mark an order as paid only because an unknown request contains:
{
"status": "success"
}
The callback must match an existing payment initiated by the platform.
Why Official APIs Win
Using official APIs provides several important advantages:
- predictable response formats
- structured error codes
- authenticated requests
- official transaction callbacks
- payment status verification
- transaction references
- better auditability
- more reliable production infrastructure
There is no need to parse HTML pages, inspect button positions, or simulate user interaction.
Everything happens through structured interfaces designed for application-to-application communication.
Designing the System for Multiple Countries
Although this project focuses on Kenya and M-PESA, the architecture is intentionally payment-provider independent.
Only the payment adapter changes.
The Binance order engine, callback workflow, transaction storage, duplicate protection, logging, and chat integration can remain largely the same.
| Country | Payment Provider |
|---|---|
| 🇰🇪 Kenya | M-PESA through Safaricom Daraja API |
| 🇮🇳 India | IMPS and NEFT payment APIs |
| 🇧🇷 Brazil | PIX integrations |
| 🇳🇬 Nigeria | Local banking APIs |
| 🇵🇰 Pakistan | Local banking gateways |
A shared payment interface might look like this:
from typing import Protocol
class PaymentProvider(Protocol):
def send_payment(
self,
recipient: str,
amount: str,
reference: str,
) -> dict:
"""Create a payment request."""
def check_status(self, transaction_id: str) -> dict:
"""Return the latest known payment status."""
def process_callback(self, payload: dict) -> dict:
"""Validate and normalize a provider callback."""
The M-PESA adapter implements this interface using Daraja.
A different country integration can implement the same interface using its own banking provider.
Separating the Payment Engine from Binance
The Binance integration should not contain Daraja-specific logic.
Similarly, the Daraja module should not need to understand Binance order internals.
A clean separation may look like this:
Binance Adapter
│
▼
Order Service
│
▼
Payment Engine
│
▼
Provider Adapter
│
▼
Daraja API
The payment engine receives a normalized instruction:
{
"order_id": "123456789",
"currency": "KES",
"amount": "1295.00",
"recipient": "2547XXXXXXX",
"reference": "BINANCE-123456789"
}
It then selects the configured provider and processes the transaction.
This design makes the system easier to reuse outside Binance P2P as well.
Monitoring and Operational Visibility
Payment automation should always provide clear operational visibility.
An internal dashboard or log panel can display statuses such as:
Payment Accepted
Waiting for Callback
Callback Received
Transaction Verified
Order Updated
Useful metrics include:
- total orders detected
- pending payments
- successful payments
- failed payments
- average callback time
- duplicate callbacks
- transactions requiring manual review
- Binance update failures
These metrics help identify whether a problem belongs to:
- Binance
- the payment provider
- the callback server
- the application database
- the network
- account configuration
Important Safety Rules
Financial automation should fail safely.
Some useful rules include:
- never pay the same order twice
- never trust an unverified callback
- never mark an order as paid before payment confirmation
- never expose API credentials in logs
- never automatically retry an uncertain payment
- always keep an audit trail
- allow manual review for ambiguous transaction states
- verify amount and recipient before payment
- use separate sandbox and production configurations
Automation should reduce repetitive work without removing transaction controls.
Lessons Learned
Building payment automation is less about writing API requests and more about designing reliable workflows.
The biggest challenges are usually:
- handling asynchronous callbacks
- preventing duplicate processing
- maintaining transaction integrity
- designing useful logs
- recovering after temporary failures
- reconciling uncertain payment states
- separating provider-specific logic
- keeping production credentials secure
These details determine whether a system merely works during a demo or remains reliable in production.
Final Thoughts
Automating Binance P2P payments isn't about replacing the trader.
It's about removing repetitive work while keeping every transaction transparent, verifiable, and based on official infrastructure.
Using the Binance integration together with the Safaricom Daraja API makes it possible to build a payment workflow that is more reliable than browser automation and easier to extend to additional payment providers.
The main engineering challenge is not sending the initial API request.
The real challenge is building a system that can safely answer these questions:
Was the payment actually completed?
Has this order already been processed?
Can the callback be trusted?
What should happen when the payment result is unknown?
Can the system recover without sending money twice?
Those are the questions that turn a payment script into a real payment automation platform.
More information about the Kenya implementation and its architecture is available here:
👉 Binance P2P M-PESA Payment Bot for Kenya:
https://py-dev.top/application-software/binance-p2p-bot-kenya
Top comments (0)