Integrating a system with email, invoicing and payments - how we tie it together
The most common integrations for custom applications, how we tie them together, what drives up the cost and which pitfalls to avoid. Practice from the C3S.PL studio.
An integration is the connection between your application and an external system - invoicing, payments, email or a courier - so that data flows automatically instead of being copied by hand. This is usually where a custom system delivers the most time savings, but it is also one of the main cost drivers. Below is how we tie it together and what to watch out for.
The most common integrations
- Invoicing - automatic issuing of invoices from data in the system.
- Payments - payment gateways, transaction statuses.
- Email (IMAP/SMTP) - sending and linking correspondence to contacts, e.g. in a CRM. → Dedicated B2B CRM
- Couriers / logistics - labels, shipment statuses.
- Accounting - exporting data to accounting systems.
How we tie them together
An integration works most reliably when the external system has a good, well-documented API. We then connect the systems, handle errors (what happens when the other side does not respond) and test on real data. Things get harder when the API is poor or unstable - then the integration costs more and requires workarounds.
What drives up the cost
- A weak or undocumented API on the external system's side.
- A requirement for real-time synchronization (instead of periodic).
- Many edge cases and errors to handle.
This is one of the main pricing factors. → How much does a custom application cost
Pitfalls
The most common one: assuming that an integration built once works forever. External providers change their APIs - that is why integrations require monitoring and maintenance. → Application maintenance after deployment
Types of integration and how they are implemented (API, webhooks)
Most integrations are based on two patterns that complement each other well.
The first is a request-response API. Your application sends a request to the external system and waits for a response - for example "issue an invoice with these line items" or "fetch the shipment status". The initiative is on your side, so you control when and what you ask. The downside is that to learn about a change you have to query (so-called polling), which can be inefficient with frequent checks.
The second is webhooks. Here the roles are reversed: it is the provider that notifies your application when something happens. A customer paid for an order, a courier picked up a parcel, an invoice changed status - the provider sends a request to an address (URL) you specify. Webhooks are efficient because they eliminate constant polling, but they require a publicly accessible receiving endpoint and careful handling (more on that below).
In practice both approaches are tied together. The API serves to perform actions, webhooks - to react to events we did not trigger ourselves. A third, simpler variant is file export or import (e.g. a periodic export of data to an accounting system), used when the other side does not provide a modern API. The choice of pattern depends on what the provider offers - and this often determines the amount of work. → Custom application - a guide
Payment integration (e.g. Stripe/PayU) step by step
Payments are the integration where mistakes cost the most, because they involve the customer's money. The scheme is usually similar regardless of the provider.
- Payment initiation. The application creates a payment object in the gateway (amount, currency, order data) and receives an identifier and an address to which the customer is directed.
- Redirect or form. The customer pays on the gateway's side or through an embedded, certified form. The key principle: card data does not pass through your server, which radically reduces the scope of security requirements.
- Return and confirmation. After payment the customer returns to the application. A caveat here - the customer's return is not a reliable source of information about the payment. The customer may close the tab before the redirect.
- Webhook as the source of truth. We change the order status only based on a webhook from the gateway, confirming that the funds were actually booked.
The most common mistake is marking an order as paid based on the customer's return instead of the webhook. The second is failing to verify the webhook signature - without it someone could impersonate the gateway. The third is ignoring idempotency, so that a webhook sent twice creates two orders. Safe handling of payment data is also a broader topic. → Data security in an application
Invoicing and email integration (transactional email)
Invoicing is usually tied to an accounting system or an invoice-issuing service via API. The application passes the order data (counterparty, line items, VAT rates), and the system returns the invoice number and a PDF document. It is important that numbering and tax data are created on the side of the system responsible for compliance, rather than being invented in the application. Typical pitfalls are amount rounding, handling corrections and different VAT rates - it is worth testing them on real cases before they reach production.
Transactional email means emails triggered by an event: order confirmation, an invoice as an attachment, a password reset. It differs from a newsletter in that it must arrive reliably and quickly. In practice it is sent through a transactional email provider with a ready-made API, which removes the deliverability problem. To keep messages out of spam, SPF, DKIM and DMARC records are configured for the sender's domain. A separate thread is receiving email (IMAP) - for example linking incoming correspondence to contacts in a CRM. This can be troublesome, because message formats are unpredictable and parsing the content requires handling many exceptions.
Error handling, retries and idempotency
An integration connects systems over which you do not have full control, so the design assumption is: the other side will fail to respond at some point. What matters is how the application behaves then.
- Retry. Transient errors (timeout, momentary unavailability) are worth retrying automatically, ideally with an increasing interval between attempts (so-called backoff), so as not to hammer an overloaded provider.
- Idempotency. Since we retry requests, we have to ensure that a repeated request does not perform the action twice. An idempotency key serves this purpose - a unique identifier of the operation by which the provider recognizes that it is the same action, and does not charge the customer a second time or create a duplicate invoice.
- Queues and deferred processing. Heavier operations (sending an email, generating an invoice) are better performed outside the main request, in the background, so that an error in one integration does not block the user's entire action.
- Logging and alerts. It is worth recording every request and its result, and informing the team about recurring errors. Without this, integration failures only come to light when a customer complains.
It is precisely these edge cases, not the "happy path", that consume most of the time and are the main reason why a solid integration costs more than it initially seems.
FAQ
What systems can a custom application be integrated with? Most often with invoicing, payment gateways, email (IMAP/SMTP), courier APIs and accounting systems. The scope depends on the API availability of a given provider.
What drives up the cost of integration? The lack of a good API on the external system's side, the need to handle many error cases, and a requirement for real-time synchronization. The worse the API documentation, the more expensive the integration.
Can an integration break over time? Yes - when an external provider changes its API. That is why integrations require monitoring and periodic maintenance, included in the post-deployment costs.
How does integration via API differ from webhooks? An API means requests initiated by your application (you ask, the provider responds). A webhook is a notification sent by the provider when something happens (e.g. an invoice is paid). In practice both are combined: API for actions, webhook for reacting to events.
What is idempotency and why does it matter for payments? Idempotency means that the same request executed multiple times produces the same effect as a single execution. For payments it protects against charging the customer twice when a request is repeated after a dropped connection. It is implemented with an idempotency key sent in the header.
Do you need your own SMTP server to send transactional emails? It is not necessary. In practice a transactional email provider with a ready-made API is used more often, which removes the problem of deliverability and the configuration of SPF, DKIM and DMARC. Your own SMTP is justified only when there are specific data requirements.
Let us turn it into a working app.
Free consultation and a quote within 48h - no obligations, with clear ranges.