The Architecture Audit: Moniepoint POS API
Audit Series #1 Focus: Async Flows, Status Gaps, and Reference Ambiguity

Executive Summary
Moniepoint's POS API documentation is technically solid. The architecture makes sound choices, asynchronous patterns, webhook notifications for real time updates, and a clean scope-based authentication model. But the documentation doesn't fully explain how these pieces work together.
The current docs focus on what each endpoint does, but leave out the how. Specifically, how a transaction moves from from initiation to confirmation, what the two status fields actually mean, and what developers need to know about the references they receive and send.
This audit identifies five specific gaps and recommends practical fixes for each.
The Findings
No guidance on how often to check transaction status
When a transaction is submitted, Moniepoint returns a 202 Accepted response, meaning "we got it, but it's still being processed." Developers then need to check back using a GET endpoint to find out the final status.
The problem: The docs warn that checking too frequently may trigger rate limiting, but they don't say how frequently is too frequent, or what the right approach is.
What's missing:
• A note that the 202 response returns no body the merchantReference is the only handle developers have to retrieve transaction status later
• A recommended polling schedule (e.g. check at 2s, then 5s, then 15s)
• An explanation of when to stop polling and treat a transaction as failed
• A sequence diagram showing the full push → poll → webhook flow
Webhook events can arrive more than once and the docs don't say so
In distributed systems, it's common, and expected, for webhook notifications to be delivered more than once. This is standard practice, not a bug. Moniepoint's own resend endpoint confirms this, it explicitly supports resending PENDING and FAILED events, meaning duplicate delivery is a built-in feature of the system.
The practical consequence here is lower-stakes than in some payment systems, since this API initiates a payment rather than recording a credit, a duplicate webhook means a duplicate notification, not a duplicate charge. But it can still cause problems: a merchant system that hasn't accounted for duplicates may trigger redundant fulfilment logic, send a customer two confirmation messages, or update an order status incorrectly.
The docs mention merchantReference but don't explain its role in identifying whether an incoming webhook has already been processed.
What's missing:
• A clear statement that duplicate webhook delivery can and will occur
• Guidance on using merchantReference as the idempotency key to detect and safely ignore duplicate events
• A note on what downstream effects to guard against in the merchant's own system
Two status fields with no explanation of which one to trust
Transaction responses include two separate status fields: processingStatus and queueStatus. The docs list both, but don't explain the relationship between them.
For example: if queueStatus is SUCCESS but processingStatus is PENDING, what does that mean? Should the developer consider the transaction complete? Still waiting? At risk of failing?
Without clarity here, developers add extra defensive code "just in case", which slows down the payment flow and introduces unnecessary complexity.
What's missing:
• A plain-language explanation of what each status field represents
• A state map showing the possible combinations and what each one means
• A clear rule for which field is the definitive source of truth
Two transaction references exist, but only one is explained
The transaction flow involves two distinct reference identifiers. The merchantReference is generated by the developer and sent with the initial request. The transactionReference is generated by Moniepoint and returned in the transaction details response once payment is complete.
These are not the same thing, and they serve different purposes, but the documentation never explains the distinction. The transactionReference appears in the GET response payload, and a developer could easily overlook it or conflate it with the merchantReference they already sent.
This matters because the transactionReference is Moniepoint's own record of the transaction. It is the authoritative identifier on Moniepoint's side, useful for support queries, reconciliation, and audit trails. A developer who doesn't know it exists won't store it, and will have a much harder time resolving disputes or tracing failed payments.
What's missing:
• A clear explanation of the difference between merchantReference and transactionReference
• A note that transactionReference is Moniepoint's identifier and should be stored by the merchant system
• Guidance on when each reference should be used, e.g. merchantReference for polling, transactionReference for reconciliation and support
The 202 response returns no body, and the docs don't say so
When a developer pushes a transaction using POST /v1/transactions, the API returns a 202 Accepted response with no body. No transaction ID, no confirmation token, nothing.
This means the merchantReference the developer sends in the request is the only way to look up that transaction later. If it isn't unique, stored, or retrievable, the developer has no way to check what happened.
The docs don't flag this dependency. The merchantReference field is listed as a required string, but its critical role as the sole transaction identifier after submission is never explained.
What's missing:
• An explicit note that the 202 response returns no body
• A clear statement that merchantReference is the only handle for retrieving transaction status after submission
• Guidance on merchantReference format, it should be unique per transaction and stored on the client side before the request is sent
Recommendations
These five changes would significantly reduce integration friction:
1. Add a transaction lifecycle diagram showing the push → poll → webhook sequence with timing.
2. Document a recommended polling schedule with backoff intervals to prevent rate limit errors.
3. Create a status reference table that maps processingStatus and queueStatus combinations to their real-world meaning.
4. Clearly distinguish merchantReference from transactionReference, explain what each is, who generates it, and when to use it.
5. Document the empty 202 response explicitly, and make clear that merchantReference must be unique and stored client-side before submission.
API Documentation Checklist
Six questions every API documentation should be able to answer clearly:
Question | Moniepoint POS API |
For async operations, is there a visual flow and recommended polling schedule? | No, polling is mentioned but no backoff guidance is provided. |
Are ambiguous statuses (like Pending or Processing) mapped to a clear state? | No, |
Are duplicate webhook events acknowledged, and is there guidance on handling them? | No, the resend feature confirms duplicates will occur but developers are given no handling instructions. |
Are both transaction references explained, and does the doc say when to use each? | No, |
Does the 202 response document what is (and isn't) returned, and how to retrieve the transaction later? | No, the response body is empty and |
Conclusion
The Moniepoint POS API is well-built. The gaps identified in this audit are documentation gaps, not product gaps, the underlying system handles async flows, and webhook delivery correctly.
Closing these gaps means developers can integrate with confidence rather than reverse-engineering behaviour through trial and error. Better documentation reduces support overhead, speeds up integration time, and reflects the quality of the product it describes.



