A practical field guide from Automation Ace.
How to Make an HTTP POST Request in a Zapier Code Step with Headers and Parameters
Zapier's Webhooks by Zapier action handles most outbound HTTP POST requests, but there are cases where a Code step is the better tool: when the request body requires dynamic construction from multiple fields, when you need conditional logic around the request, when you are making multiple requests in sequence, or when the response requires parsing before its values are usable. Code steps in Zapier have access to a global fetch function (JavaScript) and the requests library (Python) — both capable of full HTTP control including headers, body, and authentication. This guide provides ready-to-use patterns for the most common POST request scenarios.
JavaScript: Basic POST with JSON Body
The global fetch function in Zapier JavaScript Code steps handles POST requests with a JSON body:
const response = await fetch('https://api.example.com/endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + inputData.api_token
},
body: JSON.stringify({
name: inputData.name,
email: inputData.email,
message: inputData.message
})
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`Request failed: ${response.status} ${errorBody}`);
}
const data = await response.json();
output = {
status: String(response.status),
id: data.id || '',
response: JSON.stringify(data)
};
Pass api_token, name, email, and message as input data fields mapped from previous Zap steps. The throw new Error() causes the Zap step to fail with a visible error message in the run history when the API returns a non-2xx status code — useful for debugging.
JavaScript: POST with Custom Headers
Some APIs require multiple custom headers — API keys in non-standard header names, versioning headers, or request identifiers:
const response = await fetch('https://api.example.com/webhook', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': inputData.api_key,
'X-Api-Version': '2025-01',
'X-Request-Id': inputData.request_id,
'Accept': 'application/json'
},
body: JSON.stringify({
event: inputData.event_type,
payload: {
record_id: inputData.record_id,
timestamp: new Date().toISOString()
}
})
});
const data = await response.json();
output = { success: response.ok ? 'true' : 'false', response_id: data.id || '' };
JavaScript: POST with Basic Auth
For APIs that use HTTP Basic authentication (username and password encoded in the Authorization header):
const credentials = btoa(inputData.username + ':' + inputData.password);
const response = await fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + credentials
},
body: JSON.stringify({ data: inputData.payload })
});
const data = await response.json();
output = { status: String(response.status), result: JSON.stringify(data) };
btoa() is available as a global in Zapier's JavaScript Code step environment for base64 encoding.
JavaScript: POST with Form-Encoded Body
Some APIs — particularly OAuth token endpoints and legacy systems — expect application/x-www-form-urlencoded bodies rather than JSON:
const params = new URLSearchParams({
grant_type: 'client_credentials',
client_id: inputData.client_id,
client_secret: inputData.client_secret,
scope: 'read write'
});
const response = await fetch('https://api.example.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: params.toString()
});
const data = await response.json();
output = { access_token: data.access_token || '', expires_in: String(data.expires_in || '') };
Python: POST with JSON Body and Bearer Token
For Python Code steps, the requests library is available and handles JSON bodies and headers cleanly:
import requests
url = 'https://api.example.com/endpoint'
headers = {
'Authorization': f"Bearer {input_data['api_token']}",
'Content-Type': 'application/json'
}
payload = {
'name': input_data['name'],
'email': input_data['email'],
'source': 'zapier'
}
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status() # raises exception on 4xx/5xx
data = response.json()
return {
'status': str(response.status_code),
'id': str(data.get('id', '')),
'response': str(data)
}
The requests library's json=payload parameter automatically serializes the payload and sets Content-Type: application/json. raise_for_status() causes the Code step to fail visibly on non-2xx responses. For a full reference of available Python libraries, see Python libraries in Zapier Code steps.
When to Use a Code Step vs. Webhooks by Zapier for POST Requests
Use Webhooks by Zapier when the POST request is straightforward — a single endpoint, simple headers, and a flat request body that maps directly from Zap fields. Webhooks by Zapier handles this with no code required. See how to use APIs in Zapier steps for configuration details.
Use a Code step when:
- The request body needs dynamic construction — nested objects, arrays, conditional fields
- You need to make multiple sequential POST requests and use the response from one to build the next
- You need response parsing logic before the data is usable in downstream steps
- Error handling needs to be more nuanced than "fail the Zap on non-2xx"
- You want to fire the request to the Zapier Storage API or another internal Zapier service
The global fetch in Zapier's JavaScript Code steps is a full HTTP client — headers, body, method, authentication, and response handling all work as expected. Once you have the pattern for a POST with a JSON body and Bearer token, almost every API call you will ever need follows the same structure with minor variations in the header names and body shape.
For the GET request equivalent, see how to make an HTTP GET request in a Zapier Code step. For more on what is available in JavaScript Code steps, see JavaScript libraries in Zapier Code steps. For help building an API integration workflow, talk to Automation Ace.
Disclaimer: This article may include links to apps, products, or services. Some links may be affiliate links, which means Automation Ace may earn a commission at no extra cost to you.