This goes deeper than the overview in what is AI automation. No coding required, but you should be willing to look at a payload.
In short
- API = pull (you ask). Webhook = push (they tell you). JSON = the wording.
- Status codes tell you whose fault it is. Learn six of them and you can debug alone.
- Webhooks can arrive twice, late or out of order. Design for that from day one.
- If a webhook triggers anything meaningful, verify that it really came from who you think.
- Three kinds of empty — missing key,
null, empty string — are three different bugs.
An API request has four parts
Every request, in any tool, is the same four things.
| Part | Plain meaning | Example |
|---|---|---|
| Method | The verb: what do you want done? | GET, POST, PATCH, DELETE |
| URL | The address of the thing | https://api.example.com/v1/contacts/482 |
| Headers | Metadata about the request, including who you are | Authorization: Bearer abc123 |
| Body | The data you're sending, usually JSON | {"stage": "Qualified"} |
The methods you will actually use: GET reads and changes nothing, so it is safe to repeat. POST creates or triggers, and repeating it usually creates a duplicate. PUT typically replaces a whole record while PATCH changes only the fields you send — sending PUT when you meant PATCH is a classic way to wipe fields you never touched. DELETE is exactly as permanent as it sounds.
That safe/unsafe split matters for retries: re-running a GET is free, re-running a POST after a timeout may create a second deal.
Status codes: whose fault is it?
MDN groups status codes into five classes: informational (100–199), successful (200–299), redirection (300–399), client errors (400–499) and server errors (500–599) (MDN). The practical read: 4xx is your fault, 5xx is theirs.
| Code | MDN's meaning | What it means for you |
|---|---|---|
| 200 OK | The request succeeded | Done. Check the body anyway — success can still return zero results |
| 201 Created | Succeeded and a new resource was created | Your record exists. Save the returned ID |
| 400 Bad Request | The server can't process it, perceived as a client error | Your JSON or field values are wrong. Read the error body |
| 401 Unauthorized | The client must authenticate itself | Missing, wrong or expired credentials |
| 403 Forbidden | The client doesn't have access rights | Credentials work; this account isn't allowed to do this |
| 404 Not Found | The server can't find the requested resource | Wrong URL, or the record ID doesn't exist |
| 429 Too Many Requests | Too many requests in a given amount of time | Slow down. See below |
| 500 Internal Server Error | The server hit a situation it can't handle | Not your bug. Retry later, and alert someone |
The 401 versus 403 distinction saves hours: 401 means "I don't know who you are," 403 means "I know exactly who you are, and no." One is a credentials problem, the other a permissions problem, and they have completely different fixes.
Rate limits and how to back off
MDN describes 429 Too Many Requests as indicating the client "has sent too many requests in a given amount of time," a mechanism commonly called rate limiting, and notes that a Retry-After header may be included "to indicate how long a client should wait before making the request again" (MDN).
So the correct behaviour on a 429 is specific: read Retry-After if present and wait exactly that long rather than guessing; otherwise back off exponentially (1s, 2s, 4s, 8s, with a cap); limit the number of retries and send the item to an error queue instead of looping forever; and only retry safe operations automatically, because a retried POST duplicates records unless the API supports an idempotency key.
Batch jobs are where this bites. Enriching 5,000 records in a loop with no delay will hit a limit, and a workflow that treats 429 as a hard failure silently skips a thousand rows — see error handling for production workflows.
Authentication, briefly
Four patterns cover almost everything: an API key in a header such as X-API-Key: abc123; a bearer token as Authorization: Bearer abc123, the most common; basic auth with an encoded username and password, still common in internal tools; and OAuth, where you click "Connect" and the tool stores a token that refreshes — best for user-permissioned access, and expiring tokens are a real failure mode.
Two rules, no exceptions. Never put a key in a URL — URLs land in logs, browser history and error reports. And use the tool's credentials store rather than pasting keys into node fields, so you can rotate a key without editing twenty workflows.
Pagination: why you only got 100 records
Most APIs refuse to return everything at once. They hand you a page plus a way to ask for the next one — a page number, an offset, or a cursor token in the response. The symptom of getting this wrong is distinctive: your sync works perfectly and quietly handles exactly 100 records, forever. Before trusting any "get all" step, compare against the total count in the source system.
Webhooks: the part everyone underestimates
A webhook is a URL you give to another system so it can POST data to you when something happens. No polling, no delay. That's the easy part. The hard part is that webhook delivery is not as reliable as people assume, and well-written provider documentation says so out loud.
Stripe's webhook documentation is a good reference because it is explicit about delivery behaviour (Stripe):
- Retries. Stripe attempts delivery for up to three days with exponential back-off in live mode when your endpoint doesn't succeed.
- Duplicates. Endpoints "might occasionally receive the same event more than once." The defence: log the event IDs you've processed and skip ones already handled.
- Order. Stripe doesn't guarantee events arrive in the order they were generated, and warns against using the
createdtimestamp to determine order or detect duplicates — use event IDs. - Respond fast. Your endpoint must return a 2xx before any complex logic that could time out. Do the slow work after acknowledging.
- Redirects count as failures. A
3xxresponse is treated as a failure; point the sender at the final URL. - Process asynchronously. Queue events rather than handling them synchronously, because spikes overwhelm a synchronous endpoint.
Those behaviours are typical of serious webhook providers, not unique to Stripe. Three habits prevent most webhook incidents: acknowledge first and work second (return 200, then process); make handling idempotent by checking whether you already processed this event ID, so "create a lead if one doesn't already exist" survives duplicates where "create a lead" does not; and never assume order — re-fetch current state from the API when sequence matters.
Verifying that a webhook is real
Your webhook URL is a public address. Anyone who learns it can post to it, and if that triggers a CRM write or an email, you have a problem.
Stripe signs every event with a Stripe-Signature header holding a timestamp and one or more signatures, computed as an HMAC with SHA-256 over the timestamp plus the raw request body and checked against an endpoint signing secret. Its libraries apply a default five-minute tolerance on that timestamp to limit replay attacks, and the docs also recommend IP allowlisting as a second protection (Stripe).
In no-code terms: use the provider's verification step if there is one; otherwise require a shared secret in a header and reject anything without it. An unauthenticated webhook that only writes to a log is fine. An unauthenticated webhook that sends messages is not.
Test URL vs production URL
A classic beginner trap with an exact explanation. n8n's Webhook node documentation describes two URLs: the test URL, which shows incoming data in the editor when you click Listen for Test Event, and the production URL, which registers when you publish the workflow and whose runs appear in the Executions tab instead. The node accepts DELETE, GET, HEAD, PATCH, POST and PUT, offers Basic auth, Header auth, JWT auth or none, supports an IP allowlist, and can respond immediately, when the last node finishes, via a Respond to Webhook node, or as a stream (n8n).
"It worked while I was building it and stopped afterwards" is almost always a test URL left in production. More on this in n8n webhooks explained and the broader tool in what is n8n.
Reading JSON without fear
MDN defines JSON as "a standard text-based format for representing structured data based on JavaScript object syntax," and notes it can hold strings, numbers, true, false, null, objects and arrays — but not functions, dates as real date objects, undefined, NaN or Infinity (MDN).
{
"id": "L-1042",
"created_at": "2026-09-17T14:02:00Z",
"score": 82,
"qualified": true,
"owner": null,
"company": {
"name": "Northside Lending",
"branches": 12
},
"tags": ["inbound", "webinar"],
"contacts": [
{ "name": "Ana Torres", "role": "COO", "email": "ana@example.com" },
{ "name": "Luis Peña", "role": "Ops Manager", "email": "" }
]
}
Four things to notice, because they cause most real bugs:
1. Curly braces vs square brackets. {} is an object — named fields. [] is an array — an ordered list. An array of one item is still an array, and a step expecting an object will choke on it.
2. Paths. You reach a value by walking the structure: company.name is "Northside Lending", contacts[0].email is Ana's address, tags[1] is "webinar". Arrays start at 0 — the most common off-by-one in no-code automation.
3. The three kinds of empty. These are not the same thing, and confusing them creates bugs that only appear on certain records:
| Form | Meaning | Typical cause |
|---|---|---|
| Key missing entirely | The system never had this concept for this record | Different object type, or an older API version |
"owner": null | The field exists and is deliberately empty | Unassigned |
"email": "" | The field exists and holds an empty string | Someone saved a blank form field |
A filter that checks "email is not empty" but not "email exists" will happily pass records straight into a send step.
4. Types are not decoration. 82 is a number, "82" is a string; true is a boolean, "true" is a string. Comparisons and maths fail silently across that line. Dates are just strings — insist on the ISO 8601 form above (2026-09-17T14:02:00Z, where Z means UTC) whenever you control the format.
The MitHub integration contract
Fill this in before connecting any two systems. Ten minutes here saves a week of mystery.
| Field | What to write |
|---|---|
| Direction | Pull (API) or push (webhook)? |
| Trigger | What event starts it, and what is the expected volume per hour? |
| Identity | Auth method, where the credential is stored, when it expires |
| Unique key | The field that identifies a record in both systems |
| Required fields | What must be present, or the record goes to the exception queue |
| Field map | Source field → destination field, with type and transformation |
| Duplicate rule | What happens when the same event arrives twice |
| Order rule | What breaks if events arrive out of order |
| Limits | Rate limit and page size, and how you respect them |
| Failure path | Retry policy, error queue, who gets alerted |
| Verification | How you confirm the business result in the destination system |
The last row is the MitHub habit that matters most: a green run is not a result. Open the destination record and look. If that destination is your CRM, CRM architecture covers what "correct" means there.
A 20-minute drill
Do it once, today.
- Get a webhook URL from your automation tool and send it something from a test form. Watch the payload arrive.
- Read the JSON. Write down the path to three fields, including one inside an array.
- Break it on purpose. Send a payload with a field missing and another with an empty string. See what your steps do.
- Make one API call to a system you already use — a
GETfor a single record. Read the status code and the body. - Break the auth. Remove a character from the key and confirm you get a 401, not a 500. Now you know what that looks like at 2am.
Deliberately causing five errors teaches more than ten successful runs — the practice loop behind how to learn AI automation.
Five mistakes to stop making
- Trusting a 200. It means the request was accepted, not that the business outcome is correct.
- Ignoring pagination. Compare totals with the source system.
- Retrying
POSTblindly. Duplicates are worse than failures, because nobody notices them. - Leaving a webhook unverified. If it can act, it can be abused.
- Assuming the payload shape never changes. Validate required fields on arrival; route the rest to an exception queue.
None of this requires you to become a developer. It requires literacy in the three formats your systems already speak — the capability that moves you from doing tasks to designing systems. The free foundations of the Faculty of Revenue Reverse Engineering put that literacy to work on a real revenue process.
