An API (Application Programming Interface) is how two pieces of software communicate. When your app processes a payment with Stripe, sends email through SendGrid, or gets an AI response from OpenAI — that's an API call.
If Cartara flagged this concept in your diff, you likely added or modified code that calls an external service, defines API routes, or handles responses.
What Is an API?
Think of an API like a waiter at a restaurant. You don't walk into the kitchen and cook your own food — you tell the waiter what you want, the waiter communicates it, and the result comes back to you. The API is the waiter: it takes your request, passes it to another system, and returns the result.
APIs let you build on top of existing services instead of building everything yourself:
- Payments → Stripe's API
- Email → SendGrid or Resend's API
- Authentication → Clerk or Supabase's API
- AI → OpenAI or Anthropic's API
How REST APIs Work
REST (Representational State Transfer) is the most common API style. Nearly every web service uses it.
Resources and Endpoints
A REST API is organised around resources — the things your app works with (users, orders, products). Each resource has a URL called an endpoint, and you interact with it using HTTP methods:
| Method | What It Does | Example |
|---|---|---|
| GET | Retrieve data | Fetch a user's profile |
| POST | Create something | Submit a new order |
| PUT / PATCH | Update something | Edit a user's email |
| DELETE | Remove something | Delete a record |
A typical set of endpoints for a users resource:
```
GET /users → list all users
GET /users/42 → get user with ID 42
POST /users → create a new user
PUT /users/42 → update user 42
DELETE /users/42 → delete user 42
```
A Real API Call
When your app asks OpenAI to generate text, it sends a POST request:
```
POST https://api.openai.com/v1/chat/completions
Authorization: Bearer sk-your-api-key
Content-Type: application/json
{
"model": "gpt-4o",
"messages": [{ "role": "user", "content": "Summarise this article..." }]
}
```
OpenAI processes it and responds:
```json
{
"choices": [{
"message": { "content": "Here is the summary..." }
}]
}
```
This request-response pattern — send a request, get a response — is how every REST API works.
Status Codes
Every API response includes a status code telling you what happened:
| Code | Meaning |
|---|---|
| 200 | Success |
| 201 | Created successfully |
| 400 | Bad request — something wrong with what you sent |
| 401 | Unauthorised — API key missing or invalid |
| 403 | Forbidden — you don't have permission |
| 404 | Not found — the resource doesn't exist |
| 429 | Too many requests — you've hit the rate limit |
| 500 | Server error — something went wrong on their end |
When debugging an API error, the status code is the first thing to check.
Authentication
Most APIs require authentication to prove who you are. The most common methods:
API Keys — a unique string you include in every request. Simple, but store them in environment variables, never in your code. See Secrets and Config Management.
Bearer Tokens (JWTs) — a short-lived token your app gets after login, included in subsequent requests. More secure for user-facing actions.
OAuth — lets users grant your app access to their accounts on other services ("Sign in with Google"). The standard for user-authorised integrations.
What You'll See in Your Code
API-related code typically shows up in Cartara diffs as:
Fetch/axios calls — requests to external services:
```ts
const response = await fetch('https://api.stripe.com/v1/customers', {
method: 'POST',
headers: {
'Authorization': Bearer ${process.env.STRIPE_SECRET_KEY},
'Content-Type': 'application/json',
},
body: JSON.stringify({ email: user.email }),
});
```
Route handlers — your app's own API endpoints:
```ts
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
if (!user) return res.status(404).json({ error: 'User not found' });
res.json(user);
});
```
Environment variables — API keys loaded from config:
```ts
const apiKey = process.env.OPENAI_API_KEY;
```
Webhooks
Why Webhooks Exist
REST APIs work on a pull model: you ask, they answer. But what if you need to know when something happens on their end?
You could keep asking "Has the payment gone through?" every second — this is called polling and it's wasteful. A webhook flips the model: you give the service a URL, and it notifies you when something happens.
REST is a phone call — you dial, you ask, you get an answer.
A webhook is a push notification — they ping you when something occurs.
How Webhooks Work
- You register a URL in the service's dashboard (e.g.
https://yourapp.com/webhooks/stripe) - An event occurs on their platform (payment completes, user signs up)
- They send a
POSTrequest to your URL with event data - Your app processes it and responds with
200to confirm receipt
Example Stripe webhook payload:
```json
{
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_abc123",
"amount": 4999,
"currency": "usd"
}
}
}
```
Webhook Security
Anyone can send a POST request to your webhook URL — always verify the request came from the real service. Most providers sign payloads with a secret key (HMAC signature). Always verify this signature before processing the event.
When to Use Each
| Scenario | Use |
|---|---|
| Fetch a user's profile | REST (GET) |
| Create a new record | REST (POST) |
| React to a completed payment | Webhook |
| React to a new GitHub commit | Webhook |
Rule of thumb: REST when you're initiating an action. Webhooks when you need to react to something that happened elsewhere.
Other API Types
GraphQL — the client specifies exactly what data it needs in a single query. Popular with complex frontends; used by GitHub and Shopify.
WebSockets — a persistent two-way connection for real-time features: live chat, collaborative editing, live dashboards. See WebSockets and Real-Time Communication.
gRPC — high-performance protocol mostly used for internal service-to-service communication.