Skip to main content
This guide shows how to connect Zapier to 8call using OAuth2 Authorization Code flow and a single REST Hook trigger, call.completed. It covers all related endpoints, required headers, payload formats, and verification steps needed for Zapier App Review.

Overview

  • Authentication: OAuth2 Authorization Code with Bearer tokens.
  • Trigger (REST Hook): call.completed (the only event documented and exposed to Zapier).
  • Perform List: GET {API_URL}/calls/recent provides call samples to configure the trigger.
  • Webhooks: Zapier subscribes using POST {API_URL}/webhooks/subscribe and unsubscribes with DELETE {API_URL}/webhooks/subscribe.
  • Security: Optional shared secret forwarded as X-Signature header in webhook deliveries.

Authorize URL

GET {API_URL}/oauth/authorize

Token URL

POST {API_URL}/oauth/token

Userinfo (Test URL)

GET {API_URL}/oauth/userinfo

Webhook Subscribe

POST {API_URL}/webhooks/subscribe

Webhook Unsubscribe

DELETE {API_URL}/webhooks/subscribe

Perform List

GET {API_URL}/calls/recent
Replace {API_URL} with your environment’s base URL (e.g. https://api.8call.co).

Authentication and security

All Zapier → 8call requests are protected by a combination of:
  • An OAuth client ID / client secret pair
  • An OAuth bearer access token
  • Per-request client headers that identify the Zapier app
  • Client credentials: When you create the Zapier app, you configure an OAuth client in 8call that issues a client_id, client_secret, and redirect_uri. These values are also made available to your Zap to send with each API call.
  • Token exchange: Zapier exchanges the authorization code at POST {API_URL}/oauth/token using the client_id and client_secret. Only registered clients can receive access tokens.
  • Client headers: Every Zapier request to 8call must include the client identity:
    x-client-id
    string
    required
    Your 8call Zapier OAuth client ID.
    x-client-secret
    string
    required
    Your 8call Zapier OAuth client secret.
  • Bearer protection: Every authenticated request from Zapier to 8call must also include:
    Authorization
    string
    required
    Bearer {{bundle.authData.access_token}}
    On the server, 8call validates the bearer token and checks that x-client-id / x-client-secret match the configured Zapier client (ZAPIER_CLIENT_ID, ZAPIER_CLIENT_SECRET) before executing the request.
  • Protected endpoints: Webhook subscribe/unsubscribe and perform list endpoints (/webhooks/subscribe, /calls/recent) all require these headers (Authorization, x-client-id, x-client-secret). Invalid or missing credentials result in 401 Unauthorized responses.

Video walkthrough

End-to-end Zapier + 8call setup walkthrough

Prerequisites

  • A Zapier developer account with access to the Zapier Platform UI.
  • An 8call account and an OAuth client configured.
1

Create an OAuth2 app in Zapier Platform UI

Set the following in your Zapier app:
  • Authorize URL: GET {API_URL}/oauth/authorize
  • Token URL: POST {API_URL}/oauth/token
  • Refresh Token URL: same Token URL with grant_type=refresh_token
  • Test URL: GET {API_URL}/oauth/userinfo
  • Connection Label: use email from the Test URL response
Authorization
string
required
Send Bearer {{bundle.authData.access_token}} on all authenticated requests.
Use the “Test” button in Zapier to verify the user profile request succeeds.
2

Configure OAuth scopes

Supported scopes in 8call (request only what you need):
  • calls:read, calls:write
  • contacts:read, contacts:write
  • leads:read, leads:write
  • audiences:write
Least-privilege is recommended. Request the minimal set of scopes required for your Zap.
3

Set up REST Hook triggers

Each trigger uses a subscribe, unsubscribe, and perform list endpoint. All webhook requests from Zapier must include:
Authorization
string
required
Bearer {{bundle.authData.access_token}} (OAuth2 bearer token)
Content-Type
string
application/json
For the Zapier public app, 8call documents and exposes one REST Hook trigger:
  • call.completed – fired when a call handled by 8call has finished and a summary is available.

Subscribe to a webhook (POST /webhooks/subscribe)

You configure Zapier’s Subscribe URL to call POST {API_URL}/webhooks/subscribe whenever a Zap is turned on.

Request

hookUrl
string
required
Public HTTPS URL Zapier provides as your target URL.
event
string
Must be "call.completed". If Zapier hardcodes the event, you can omit this field in dev and 8call will default it to call.completed.
secret
string
Optional shared secret. If provided, deliveries include header X-Signature: {secret}.
curl -X POST '{API_URL}/webhooks/subscribe' \
  -H 'x-client-id: YOUR_CLIENT_ID' \
  -H 'x-client-secret: YOUR_CLIENT_SECRET' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "hookUrl": "https://hooks.zapier.com/hooks/standard/123/abc/",
    "event": "call.completed",
    "secret": "zapier_shared_secret_123"
  }'

Response

On success 8call returns the created subscription:
{
  "id": "b2b0f21a-7ad4-48b1-8f4b-14e2b1b5f2a2",
  "event": "call.completed",
  "callback_url": "https://hooks.zapier.com/hooks/standard/123/abc/"
}
// Subscribe using Node (fetch)
const res = await fetch('{API_URL}/webhooks/subscribe', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    hookUrl: 'https://hooks.zapier.com/hooks/standard/123/abc/',
    event: 'call.completed',
    secret: 'zapier_shared_secret_123'
  })
});
if (!res.ok) throw new Error(await res.text());
const data = await res.json();
console.log(data);

Unsubscribe from a webhook (DELETE /webhooks/subscribe)

You configure Zapier’s Unsubscribe URL to call DELETE {API_URL}/webhooks/subscribe when a Zap is turned off.

Request

hookUrl
string
required
The exact target URL to remove.
curl -X DELETE '{API_URL}/webhooks/subscribe' \
  -H 'x-client-id: YOUR_CLIENT_ID' \
  -H 'x-client-secret: YOUR_CLIENT_SECRET' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "hookUrl": "https://hooks.zapier.com/hooks/standard/123/abc/"
  }'
{
  "success": true
}

Perform List – sample calls (GET /calls/recent)

Zapier uses the Perform List URL to fetch a small array of sample items when a user creates the Zap. For the call.completed trigger, configure the Perform List URL to GET {API_URL}/calls/recent.
  • Recent calls
curl -X GET '{API_URL}/calls/recent' \
  -H 'x-client-id: YOUR_CLIENT_ID' \
  -H 'x-client-secret: YOUR_CLIENT_SECRET' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
[
  {
    "id": "c9d0a1a0-4c47-4e9f-9b9f-2c6e4a9dbe00",
    "created_at": "2025-01-15T10:30:00Z",
    "summary": "Answered, discussed pricing, requested follow-up."
  }
]
// Fetch recent calls for use in a Zapier Perform List
const res = await fetch(`${process.env.API_URL}/calls/recent`, {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.ACCESS_TOKEN}`,
  },
});
if (!res.ok) {
  throw new Error(`Failed to fetch recent calls: ${res.status} ${await res.text()}`);
}
const calls = await res.json();
console.log('Recent calls:', calls);

Webhook deliveries

8call will send an HTTP POST to your subscribed callback_url with:
  • Header X-Event: {event}
  • Header X-Signature: {secret} when a secret was provided at subscription time
  • JSON body containing the event payload
X-Signature is a simple shared-secret echo. It is not an HMAC. Verify equality on receipt if you supplied a secret during subscription.

Example delivery: call.completed

The HTTP POST body for a call.completed webhook is a single JSON object representing the completed call:
{
  "id": "c9d0a1a0-4c47-4e9f-9b9f-2c6e4a9dbe00",
  "organization_id": "b1a2e3f4-5678-90ab-cdef-1234567890ab",
  "created_at": "2025-01-15T10:30:00Z",
  "summary": "Answered, discussed pricing, requested follow-up.",
  "duration_seconds": 245,
  "agent_id": "b3f9a8b6-7c21-4e5b-8d3a-9e1c2f4a5b6c"
}
import express from 'express';
const app = express();
app.use(express.json());

app.post('/zapier-target', (req, res) => {
  const event = req.header('X-Event');
  const signature = req.header('X-Signature');
  if (process.env.ZAPIER_SHARED_SECRET && signature !== process.env.ZAPIER_SHARED_SECRET) {
    return res.status(401).send('Invalid signature');
  }
  console.log('Event:', event, 'Payload:', req.body);
  res.status(200).send('ok');
});

OAuth endpoints

GET {API_URL}/oauth/authorize
  • Standard OAuth2 Authorization Code flow.
  • Redirects back using your registered redirect_uri with code parameter.
POST {API_URL}/oauth/token
  • Exchange the authorization code for access_token and refresh_token.
  • For refresh: send the same endpoint with grant_type=refresh_token.
GET {API_URL}/oauth/userinfo
  • Returns the authenticated user profile used for connection label.

Troubleshooting

  • 401 Unauthorized
    • Ensure Authorization: Bearer {{bundle.authData.access_token}} is present on all requests.
    • Verify your token is not expired; refresh if necessary.
    • Check that the token maps to an active user and organization in 8call.
  • 400 Bad Request (subscribe/unsubscribe)
    • Confirm hookUrl is a valid public HTTPS URL.
    • Ensure event is one of the supported values.
  • Webhooks not arriving
    • Verify your target URL is reachable from the public internet.
    • If you set a secret, confirm you’re checking X-Signature exactly.
    • Check Zapier’s Zap history to confirm the subscribe call succeeded.
  • Empty Perform List
    • You may not have recent data in your environment. Create a test call in 8call, then retry GET /calls/recent.
If you can successfully subscribe, see deliveries in your Zap’s history, and fetch Perform List samples, your Zapier integration with 8call is set up correctly.