How Two Applications Communicate Using an API

An API conversation is a request followed by a response. This practical guide shows what each part means, how a small Flask service handles JSON and what to check when the exchange fails.

Diagram showing two software applications exchanging data through an API

When one application asks another for a customer record, a delivery price or a weather forecast, the exchange often happens through an API. The idea is simple: the client sends a request in an agreed format, and the server returns a response.

The request carries four useful pieces

A web API request usually contains an address, an HTTP method, headers and sometimes a body.

URL

The location of the resource, such as /orders/42.

Method

The action: GET reads, POST creates, PUT or PATCH changes, and DELETE removes.

Headers

Extra context such as the content type, authentication token or preferred response format.

Body

The data being sent, often encoded as JSON.

Imagine that Application A needs to create a support ticket in Application B. It sends a POST request to the ticket endpoint with a JSON body containing the subject and message. Application B validates the data, stores the ticket and sends back a response.

A small Flask example

This server accepts JSON at /tickets, checks that a subject exists and returns a new ticket identifier.

from flask import Flask, request, jsonify
app = Flask(__name__)
@app.post("/tickets")
def create_ticket():
    data = request.get_json(silent=True) or {}
    if not data.get("subject"):
        return jsonify(error="subject is required"), 400
    ticket = {"id": 101, "subject": data["subject"], "status": "open"}
    return jsonify(ticket), 201

The client can send:

{
  "subject": "Printer is offline"
}

A successful response uses status 201 and returns the created ticket. A bad request uses status 400 and explains what is missing. That status and message are part of the API contract.

The response tells the client what happened

Response partWhat to check
Status code2xx usually means success, 4xx points to the request, and 5xx points to a server failure.
HeadersConfirm the content type and look for limits, caching rules or a request identifier.
BodyRead the returned data or the error details; do not rely on the status text alone.

Applications should not assume that every response is successful or even valid JSON. Networks fail, services time out and credentials expire.

Build the client for failure as well as success

Set a timeout

Do not let one slow service block the application forever.

Check the status

Handle expected outcomes such as 201, 400, 401 and 404.

Validate the body

Confirm required fields before using them.

Retry carefully

Retry temporary failures with a delay, but avoid repeating actions that could create duplicates.

Log a request ID

It makes a problem much easier to trace across two systems.

Never place passwords or private API keys in source code. Load secrets from a protected environment or secret manager, send them only over HTTPS and give each credential the least access it needs.

Test the contract from both sides

Before connecting a real client, use Flask's test client or an API testing tool to try normal, missing and invalid data. Agree on field names, status codes and error shapes. If the server changes that contract, version the API or give clients time to migrate.

  • Document one working request and its response.
  • Document common error responses.
  • Use HTTPS and protected credentials.
  • Validate input on the server and output on the client.
  • Add timeouts, useful logs and safe retry behaviour.
Found this useful?Share it with someone.
LinkedInXBluesky

Need more practical IT guides?

Explore step-by-step tutorials, expert insights, and actionable guidance to help you work smarter, stay secure, and solve real problems.

Browse More Articles