Daraja SDK Logomark
Daraja SDK
Payments & Checkout

C2B

Register callback URLs and receive real-time notifications for Customer to Business payments made to a Pay Bill or Till number.

Also called the Register URL API. Safaricom describes it as enabling merchants to receive real-time notifications for payments made to their Pay Bill or Till number.

Endpoint

https://sandbox.safaricom.co.ke/mpesa/c2b/v2/registerurl

Overview

Funds move from a customer's M-PESA wallet to a merchant's short code, triggered from SIM Toolkit, the M-PESA app, the Safaricom app, USSD, the NI Push API, or the Dynamic QR Code API. This API registers two callback URLs against your short code:

  • Validation URL, called only if you've had External Validation enabled on your short code (off by default), giving you a chance to accept or reject a payment before it completes, for example by checking an account number.
  • Confirmation URL, called after a payment has completed successfully.

Turning on Validation requires emailing apisupport@safaricom.co.ke or M-pesabusiness@safaricom.co.ke. It is not a setting you can flip from the portal directly.

How it works

Customer initiates payment to your Pay Bill or Till number.

M-PESA checks whether External Validation is enabled for your short code.

If enabled, M-PESA calls your Validation URL and waits roughly 8 seconds for a response, then completes or cancels the transaction based on what you return, or based on the registered default action if your endpoint doesn't answer in time.

If disabled (the default), M-PESA completes the transaction directly and calls your Confirmation URL.

If no URLs are registered at all, M-PESA still completes the transaction.

SMS notifications go to both customer and merchant regardless of whether your endpoints respond.

For transactions where a callback never lands, Safaricom points to the Pull Transactions API or the M-PESA Organization Portal as the fallback.

URL requirements

  • Publicly reachable IP address or domain name.
  • HTTPS required in production; HTTP is allowed in sandbox.
  • Avoid the words M-PESA, Safaricom, exe, exec, cmd, sql, query (or variants) anywhere in the URL.
  • Don't use public URL testers such as ngrok, mockbin, or requestbin in production; these are typically blocked by the gateway.

On sandbox, you can register (and overwrite) your URLs as many times as you like. In production, registration is a one-time call: changing the URLs afterward means deleting the existing ones first, from Self Service > URL Management on the portal, and re-registering.

Prerequisites

  • Daraja account and sandbox app, with a Consumer Key and Consumer Secret.
  • Test data from the simulator section for sandbox testing.
  • A live Pay Bill or Till number with Business Admin/Manager operators created, for Go Live.
  • An access token from the Authorization API.

Registering URLs

Request

{
  "ShortCode": "600984",
  "ResponseType": "Either Cancelled or Completed",
  "ConfirmationURL": "your confirmation URL",
  "ValidationURL": "your validation URL"
}
FieldDescriptionTypeSample value
ShortCodeThe Pay Bill or Till number the URLs apply to.Numeric600996
ResponseTypeWhat M-PESA does if your Validation URL is unreachable. Completed auto-accepts, Cancelled auto-rejects.StringCompleted or Cancelled
ValidationURLCalled before completion, only if External Validation is enabled.URLhttps://ip/domain:port/path
ConfirmationURLCalled after successful completion.URLhttps://ip/domain:port/path

Defect in the source material

Safaricom's own note on this field says the words Cancelled and Completed "must be in sentence case and well-spelled", which is an odd instruction to have to give about your own enum values, but it is exactly what the documentation says, so it is reproduced as written.

Response

{
  "OriginatorCoversationID": "6e86-45dd-91ac-fd5d4178ab523408729",
  "ResponseCode": "0",
  "ResponseDescription": "Success"
}

Defect in the source material

OriginatorCoversationID is spelled that way, missing the "n," in Safaricom's own response sample, and it appears consistently across their C2B documentation rather than as a one-off typo. It's kept exactly as documented, since that is the field name the response actually returns.

FieldDescriptionTypeSample value
OriginatorCoversationID (sic)Unique identifier for the request, returned by the API proxy.AlphanumericFewer than 20 characters
ResponseCodeWhether the request was accepted.Alphanumeric0
ResponseDescriptionStatus of the request.StringSuccess

Once URLs are registered, no further development is needed on your side to trigger a payment during testing: use the simulator to preview what an incoming payment looks like.

Simulating a transaction

Request

{
  "ShortCode": 600984,
  "CommandID": "Either CustomerBuyGoodsOnline or CustomerPayBillOnline",
  "Amount": 1,
  "Msisdn": 254708374149,
  "BillRefNumber": "Account reference for Customer paybills and null for customer buy goods"
}
FieldDescriptionTypeSample value
ShortCodeThe Pay Bill/Till number receiving the payment.Numeric600996
CommandIDCustomerBuyGoodsOnline for a Till payment, CustomerPayBillOnline for a Pay Bill payment.StringCustomerPayBillOnline
AmountAmount transacted.Numeric10
MsisdnThe phone number the funds are debited from. Use the sandbox test number provided.Numeric254708374149
BillRefNumberAccount reference for Pay Bill payments; usually blank for Buy Goods.String"Test Ref"

Response

{
  "OriginatorCoversationID": "53e3-4aa8-9fe0-8fb5e4092cdd3405976",
  "ResponseCode": "0",
  "ResponseDescription": "Accept the service request successfully."
}

Callback payloads

Validation request

Only sent to partners who have External Validation enabled.

{
  "TransactionType": "Pay Bill",
  "TransID": "RKL51ZDR4F",
  "TransTime": "20231121121325",
  "TransAmount": "5.00",
  "BusinessShortCode": "600966",
  "BillRefNumber": "Sample Transaction",
  "InvoiceNumber": "",
  "OrgAccountBalance": "25.00",
  "ThirdPartyTransID": "",
  "MSISDN": "2547 ***** 126",
  "FirstName": "NICHOLAS",
  "MiddleName": "",
  "LastName": ""
}
FieldDescriptionTypeSample value
TransactionTypeBuy Goods or Pay Bill.StringPay Bill
TransIDUnique M-PESA transaction ID, also sent to the customer by SMS.AlphanumericLHG31AA5TX
TransTimeYYYYMMDDHHMMSS.Timestamp20170813154301
TransAmountAmount paid. Whole numbers only.Numeric100
BusinessShortCodeThe receiving short code.String654321
BillRefNumberAccount number for Pay Bill transactions.StringUp to 20 alphanumeric characters
OrgAccountBalanceUtility account balance. Blank on validation; the post-payment balance on confirmation.Decimal30671
ThirdPartyTransIDYour own transaction ID, echoed back if supplied on a validation response.String1234567890
MSISDNMasked customer number.String2547 * 126
FirstName, MiddleName, LastNameCustomer's registered names. Can be empty.StringJohn

Accepting or rejecting a validation request

To accept, respond with ResultCode 0 and ResultDesc Accepted:

{ "ResultCode": "0", "ResultDesc": "Accepted" }

To reject, use any non-zero code from the table below and set ResultDesc to Rejected:

{ "ResultCode": "C2B00011", "ResultDesc": "Rejected" }
Result codeMeaning
C2B00011Invalid MSISDN
C2B00012Invalid account number
C2B00013Invalid amount
C2B00014Invalid KYC details
C2B00015Invalid short code
C2B00016Other error

Error codes

HTTPErrorCauseFix
500500.003.1001 Internal Server ErrorServer-side failure.Confirm your setup matches the documentation and the correct endpoint is being called.
500500.003.1001 URLs are already registeredA URL is already registered for this short code.Delete the existing one and re-register.
400400.003.01 Invalid Access TokenWrong or expired token.Regenerate the token; check for copy-paste errors.
400400.003.02 Bad RequestSomething is missing from the payload.Check the request against the documentation.
500500.003.03 Quota ViolationToo many requests per second.Slow down; one request at a time while testing.
500500.003.02 Spike Arrest ViolationYour endpoint is generating errors fast enough to trip a spike protection rule.Confirm your endpoint is up and responding correctly.
404404.003.01 Resource not foundWrong endpoint.Double check the URL.
404404.001.04 Invalid Authenticator HeaderAll Daraja APIs except Authorization are POST; Authorization is GET. Mixing this up produces this error.Use the correct HTTP method.
400400.002.05 Invalid Request PayloadMalformed body.Match the sample payload exactly.
500500.003.1001 Duplicate notification infoURLs are already registered on the older aggregator/MPLS platform, which conflicts with Daraja registration.Request deletion on the aggregator platform first.

Testing

Daraja Simulator: create a test app with the C2B product attached, register your URLs, then simulate with CustomerPayBillOnline or CustomerBuyGoodsOnline.

Postman: generate a token from https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials, then call the sandbox endpoint above. A ready-made Postman collection is available from the portal once logged in.

"Simulate C2B Request" is a sandbox-only feature; there's no equivalent simulated trigger in production, since production payments come from real customers.

Go Live

Attach the integration to a live Pay Bill or Till, using a short code, organization name, and M-PESA admin/manager username. See Organization Portal & Go Live for creating those operators. Once approved, production endpoints are emailed to the developer on the account.

FAQs

On this page