Back to blog
Tutorial

Integrations: how systems talk to each other

By Flávio Emanuel · · 9 min read

Why integrate

A system that lives in isolation forces someone to do the work manually. An order comes into the webapp, someone copies it to the shipping system. Payment confirmed, someone marks it in accounting. Customer sends a message, someone types the reply.

Every manual step is a failure point. The person forgets, enters the wrong data, types the wrong amount, forgets to update the status. And the more the business grows, the more those manual steps become bottlenecks. What works with 10 orders a day breaks with 50.

Integration eliminates this repetitive work. The system does on its own what used to depend on a person copying data from one place to another. In AutoPars, there are 5 integrations running together: payment, shipping, WhatsApp, email, and media. Each one handles a piece of the flow.

API: the entry point

API (Application Programming Interface) is the interface that lets one system talk to another. In practice: you send an HTTP request with data and receive a structured response.

Here’s how it works: your system sends a request with structured data, the other system processes it and returns a response. You don’t need to know how the other system works internally.

Real example from AutoPars: checking the status of a shipment on Melhor Envio.

GET https://api.melhorenvio.com/api/v2/me/shipment/tracking
Authorization: Bearer YOUR_TOKEN

The API responds with JSON containing the current shipment status. The system reads the response and updates the order automatically. The buyer sees “in transit” without anyone having typed anything.

The REST pattern

Most APIs you’ll run into follow the REST pattern:

  • URLs represent resources: /api/products, /api/orders/123
  • HTTP verbs indicate the action: GET = read, POST = create, PUT = update, DELETE = remove
  • Responses come in JSON

Once you understand REST, you can integrate with pretty much any modern service. The logic is always the same — the endpoint changes, the payload changes, but the pattern stays the same. And HTTP status codes follow convention: 200 is success, 201 is created, 400 is validation error, 401 is unauthenticated, 404 is not found, 500 is internal server error. Knowing how to read these codes speeds up debugging a lot when an integration isn’t working.

Webhook: real-time notification

An API is when you ask. A webhook is when the other system tells you.

The difference matters. If your system needs to know when a payment was confirmed, there are two approaches:

Polling (bad): your system asks the payment gateway every 30 seconds: “paid yet? paid yet? paid yet?” Wastes resources, it’s slow, and if the interval is too long, the customer waits for no reason.

Webhook (good): the payment gateway sends a POST to a URL on your system at the exact moment of confirmation. Instant, efficient, no waste.

In AutoPars, when a buyer pays a boleto on Asaas, the system doesn’t keep asking. Asaas sends an automatic POST:

{
  "event": "PAYMENT_CONFIRMED",
  "payment": {
    "id": "pay_123",
    "value": 299.90,
    "status": "CONFIRMED"
  }
}

The system receives it, validates the origin, updates the order, and triggers the next actions: notifies the seller via Zapi (WhatsApp) and sends a confirmation email via Resend. All automatic, in seconds.

Webhook pitfalls

Webhooks work well but need some care:

Always validate the origin. Anyone can send a POST to your webhook URL. Validate the token, signature, or sender IP. Without validation, someone could simulate a confirmed payment and release a product without paying.

Handle duplicates. The same event can arrive more than once (the provider resends if it didn’t get a 200 OK on the first attempt). Your system needs to be idempotent: receiving the same event twice can’t cause a duplicate action.

Respond fast. Return 200 OK immediately and process in the background if it’s heavy. If you take too long to respond, the provider may consider it a failure and resend.

And log everything. When something doesn’t work (and it will happen), the received webhook log is what saves you. Without logs, you’re in the dark trying to guess what went wrong.

The 5 AutoPars integrations

Asaas (payment)

The full flow: system creates a charge via API (boleto, Pix, or card) -> customer pays -> Asaas notifies via webhook -> system updates the order -> notifies seller and buyer.

What looks simple has layers. Boletos expire and need handling (resend the charge? cancel the order?). Pix confirms in real time but needs a dynamically generated QR code. Card payments can have chargebacks weeks later and need a refund in the system. Each payment method has its own logic.

In AutoPars, I implemented payment splitting: the sale amount is automatically divided between the platform (fee) and the seller (net amount). Asaas handles the split at the gateway level — the money lands already divided.

Melhor Envio (shipping)

Three steps: shipping calculation, label generation, and tracking.

The buyer enters their zip code, the system queries the Melhor Envio API with the origin zip (seller), destination zip (buyer), and product dimensions. It returns carrier options with price and estimated delivery time. The buyer picks one, and when the order is confirmed, the system generates the shipping label automatically.

Tracking works via webhook: Melhor Envio notifies when the shipment status changes (posted, in transit, out for delivery, delivered). The system updates and the buyer sees the status without anyone manually copying a tracking code.

Zapi (WhatsApp)

Automatic notifications via WhatsApp. “Your order has been confirmed”, “your part is out for delivery”, “payment received”. The system sends the message via the Zapi API. Nobody types anything manually.

WhatsApp has a much higher open rate than email. In the context of AutoPars, where the seller is an auto parts shop owner who lives on WhatsApp, getting notifications there is more effective than email.

Resend (transactional email)

Registration confirmation, password recovery, order status, invoice. Transactional email is different from marketing email — it’s email the system fires in response to a user action, not a mass campaign.

Resend has a clean API and good documentation. Implementation takes hours, not days. The email goes out formatted in HTML with a responsive template. One detail that matters: transactional email needs a verified domain with SPF and DKIM properly configured, otherwise it lands in spam. Resend makes that part easier, but it’s the dev’s responsibility to make sure the DNS setup is correct before going to production.

Cloudflare Stream (media)

Image and video uploads for products. The seller uploads the file on the frontend, the system saves it to Cloudflare with a URL optimized for global CDN. Images served from the closest point to the buyer, fast loading.

How I organize the code

With 5 integrations in the same project, organization is what keeps the code from turning into a mess. Each integration is an isolated module with its own structure:

src/
  integrations/
    asaas/
      client.ts       (base config: URL, token, headers)
      payments.ts     (create, query, cancel charges)
      webhooks.ts     (handler that receives and processes events)
    melhor-envio/
      client.ts
      shipping.ts     (shipping calculation, label generation)
      tracking.ts     (query and tracking webhook)
    whatsapp/
      client.ts
      messages.ts     (message templates, sending)
    resend/
      client.ts
      emails.ts       (templates, transactional sending)
    cloudflare/
      client.ts
      upload.ts       (image/video upload, CDN URL)

If Asaas changes their API from v2 to v3, I only touch the asaas/ folder. If I need to swap Zapi for Evolution API for WhatsApp, I replace the implementation inside whatsapp/ without touching the rest of the system. Each integration is a black box to the rest of the code.

Practices that save you headaches

API tokens go in environment variables, never in the code. If a token leaks into Git, the damage can be serious.

Have a fallback for when the external API goes down. And it will go down. Melhor Envio being offline can’t prevent a buyer from completing an order. Show a message, save the data, and process it when the service comes back.

Log every request and response. When the Asaas webhook arrives and the order doesn’t update, the log shows whether the event arrived, whether the payload was correct, and where processing failed.

5-second timeout on every external request. If the API doesn’t respond in 5 seconds, it won’t respond. Your system can’t sit there waiting.

And retry with exponential backoff for temporary failures. First attempt immediate, second at 1 second, third at 4 seconds. If it failed 3 times, log the error and send a notification.

How much this adds to a project

Each integration adds 1 to 2 weeks to development, depending on the API’s complexity and the quality of the documentation.

Well-documented APIs (Resend, Stripe) are fast. Clear docs, up-to-date SDK, working examples. I implement them in 3-4 days.

APIs with poor documentation or an outdated SDK take longer. I need to test endpoint by endpoint, discover undocumented behaviors, and handle errors the docs don’t mention.

In AutoPars with 5 integrations, this represented about 40% of total development time. For the end user it’s invisible — they click “buy” and everything happens. But behind the scenes, 5 different systems are talking to make that click work.

If you’re planning a custom webapp, factor integrations into the budget and timeline. Every API your system needs to talk to adds real complexity.

Next step

Need a dev who truly delivers?

Whether it's a one-time project, team reinforcement, or a long-term partnership. Let's talk.

Chat on WhatsApp

I reply within 2 hours during business hours.