Quick answer
In Settings → API Keys, create a key with the right scopes and call https://api.bip.marketing with the x-bip-api-key header. POST /api/leads creates or updates contacts, POST /api/events logs events, /api/campaigns/trigger fires an API campaign and /api/campaigns/cancel cancels a pending send.
Your system already knows when someone signs up, buys or pays. With the API, BIP knows it the same instant: the contact is updated, the purchase goes into their history and the right message goes out to that person. This guide shows you how to get the integration live. The full reference for every endpoint is at bipmarketing.readme.io.
What you need
- Admin access to the BIP account, to create the key
- A server or back end that makes HTTPS calls (the key never goes to the browser)
- A campaign with API Trigger, if you'll send messages
- The custom fields and KPIs created in Settings, if you'll send them
- A paid plan for WhatsApp campaigns (the free plan sends email)
What you'll get
- Contacts created or updated the moment they sign up, with no spreadsheets and no duplicates.
- Welcome, confirmation or reminder messages for one person, triggered by your system in a single call.
- Purchases and other events logged in the contact's history, with value and details.
- Reminders that cancel themselves when the customer follows through: paid the order, completed the purchase.
- Tags and KPIs (revenue, orders, points) always up to date for building segments.
How it works
- 1Create an API key with the scopes your integration uses
- 2Your server calls BIP with the key in the x-bip-api-key header
- 3BIP updates the contact, logs the event or triggers the campaign
Every call goes to https://api.bip.marketing, with a JSON body. The key identifies your account, so you don't need to send the namespace.
There are four endpoints:
POST /api/leadscreates or updates a contact.POST /api/eventslogs an event (a purchase, a trial sign-up) in the contact's history.POST /api/campaigns/triggerfires an API Trigger campaign for one contact. If the contact doesn't exist yet, the same call can create it.POST /api/campaigns/cancelcancels a delayed send that hasn't gone out yet.
BIP recognizes each person by email or phone. If the contact already exists, the new data goes into the same profile: emails, phones and tags are added, and the fields you send are updated.
Step by step
1. Create the API key
- In Settings, open the API Keys tab and click Add New API Key.
- In Name, say who will use the key. For example: Loja Horizonte — website.
- Leave Active on. If you want the key to stop working on a certain date, turn on Enabled under Automatic Expiration: BIP suggests one month from today and you adjust it on the calendar.
- In Scopes, turn on only what the integration uses. The table in Scopes shows what each one unlocks.
- Click Save. The API key field appears with a copy button. Copy the key and store it on the server.
Only admins can create, edit and delete keys. In the list, each key shows its scopes and a green dot (active) or a red dot (inactive). You can copy the key again from the list whenever you need it.

Screenshot coming soon
2. Set up fields and KPIs
The API only writes custom fields and KPIs that already exist in the account. Create whatever the integration will send first.
- In Settings → General, go to Fields and click Add Field for each extra piece of data (for example, Plano, a String field for the customer's plan).
- In KPIs, click Add KPI and fill in the KPI ID (for example,
receita, for revenue) and the KPI Name (Receita). In the API, you use the ID. - Click Save.
Tags need no setup: a new tag exists in the account the first time it arrives through the API.

Screenshot coming soon
3. Send contacts with POST /api/leads
Use it when someone signs up, updates their profile or becomes a customer. The key needs the Leads Write scope (leads:write).
BIP looks up the contact by id, email or phone. If it finds one, it updates it. If it doesn't, it creates one, and then name is required.
{
"name": "Marina Alves",
"email": "marina.alves@exemplo.com",
"phone": "+5511912345678",
"tags": ["cliente", "loja-centro"],
"fields": [{ "key": "Plano", "value": "Ouro" }],
"kpis": { "receita": 349.9 },
"metadata": { "origem_cadastro": "checkout" }
}
What happens to each piece of data:
- Name: replaces the current name.
- Email and phone: new values are added to the profile. Always send the phone with
+and the country code. - Tags:
tagsadds;tagsRemoveremoves. The API never removes a tag you didn't ask it to. - Fields:
keyis the field name, as it appears in Settings. An emptyvalue("",nullor[]) clears the field on the contact. A value in the wrong format is ignored for that field only. - KPIs: the value is added to what the contact already has. Sending
{"receita": 120}to a contact at 349.90 leaves 469.90. To score contacts, create a KPI such aspointsand add to it here. - Metadata: each key you send replaces the previous one; the others stay as they are.
- Archived contacts come back to the list.
The response returns the contact's id and echoes the data you sent. Keep the id if you'll log events later.
curl -X POST https://api.bip.marketing/api/leads \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"name": "Marina Alves", "email": "marina.alves@exemplo.com", "phone": "+5511912345678", "tags": ["cliente"]}'4. Log events with POST /api/events
Use it to record what the person did outside BIP: a purchase, a trial started, a satisfaction score. The key needs the Events Write scope (events:write).
typeis free-form:purchase,trial_started,nps.- Identify the contact by
leadId(theidthat/api/leadsreturns) or bytracker(the visitor ID from the site script). The contact must already exist. valueis a string:"349.90","9".metadataholds any details you want (order number, items).
The event appears in the contact's Feed with its type, value and details under More Info. To segment buyers, send a tag or a KPI through /api/leads at the same time, as in the purchase recipe in Ready to copy.
curl -X POST https://api.bip.marketing/api/events \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"type": "purchase", "leadId": "CONTACT_ID", "value": "349.90", "metadata": {"pedido": "LH-10482"}}'5. Create the API Trigger campaign
To send a message to one person through the API, you use a campaign with API Trigger. It doesn't use a segment: each call picks the contact.
- In Campaigns, click New Campaign.
- Choose the Channel and the content: Email with an Email Template (plus up to 3 Webhooks, if you want), or WhatsApp with an approved template.
- In Schedule Type, choose API Trigger.
- In Trigger Mode, choose Immediate (the message goes out as soon as BIP receives the call) or Delay (BIP waits the number of seconds in Delay (Seconds); a new call for the same contact restarts the timer).
- In Lead Re-entry Window, decide whether the person can receive it again. By default, each contact gets the campaign once. For reminders that repeat, turn on Allow Lead Re-entry and set the Cooldown Period (Days).
- Open API Integration: BIP shows ready-made commands, already filled in with the campaign ID. The ID is also at the end of the page URL.
- Click Save → Save and Activate and confirm with Activate API Trigger.

Screenshot coming soon
6. Trigger with /api/campaigns/trigger
The key needs the Campaigns Trigger scope (campaigns:trigger). Send campaignId and lead.
lead can be:
- Text, for a contact that already exists: the email, the phone with country code, the contact ID or the visitor ID.
- Object, to create or update the contact and trigger in the same call. It accepts the same data as
/api/leadsand also requires the Leads Write scope (leads:write).
{
"campaignId": "CAMPAIGN_ID",
"lead": { "name": "Tiago Pereira", "email": "tiago.pereira@exemplo.com", "tags": ["trial"] }
}
The response confirms the contact and the mode: {"campaignId": "…", "leadId": "…", "mode": "immediate"} or "mode": "delay". The send happens right after, in the campaign queue.
For tools that can only call a URL, the same endpoint accepts GET, with campaignId, lead and api-key in the URL. In that case, identify the contact by email. For everything else, use POST.
curl -X POST https://api.bip.marketing/api/campaigns/trigger \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"campaignId": "CAMPAIGN_ID", "lead": "marina.alves@exemplo.com"}'7. Cancel a send with /api/campaigns/cancel
In a Delay campaign, the message waits. If its reason is gone (the customer paid, completed the order), cancel it. The key needs the Campaigns Trigger scope.
- Send the same
campaignIdand the contact inlead, as text. - The response returns
"cancelled": truewhen there was a pending send and it was cancelled. - It returns
"cancelled": falsewhen there was nothing to cancel: the message already went out, was never triggered, or the campaign is Immediate. That's not an error: you can call it as many times as you like. - A cancelled send doesn't count as a send.
curl -X POST https://api.bip.marketing/api/campaigns/cancel \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"campaignId": "CAMPAIGN_ID", "lead": "marina.alves@exemplo.com"}'Reference
Base URL and authentication
| Item | Value |
|---|---|
| Base URL | https://api.bip.marketing |
| Key | Header x-bip-api-key: YOUR_API_KEY |
| Key in the URL | Parameter ?api-key=YOUR_API_KEY (prefer the header) |
| Body | JSON, with Content-Type: application/json |
Endpoints
| Method | Path | Scope | Purpose |
|---|---|---|---|
| POST | /api/leads | leads:write | Create or update a contact |
| POST | /api/events | events:write | Log an event on the contact |
| GET or POST | /api/campaigns/trigger | campaigns:trigger (and leads:write with a lead object) | Trigger an API campaign for one contact |
| GET or POST | /api/campaigns/cancel | campaigns:trigger | Cancel a delayed send that's still pending |
Scopes
| In the panel | Scope | What it unlocks |
|---|---|---|
| Leads Write | leads:write | /api/leads and lead as an object in trigger |
| Events Write | events:write | /api/events |
| Campaigns Trigger | campaigns:trigger | /api/campaigns/trigger and /api/campaigns/cancel |
| Leads Read | leads:read | Reading contact data; the endpoints in this guide don't use it |
POST /api/leads fields
| Field | Type | How it works |
|---|---|---|
email | string | Identifies the contact or adds an email. Send email, phone or id. |
phone | string | International format, with + and the country code: +5511912345678. |
id | string | ID of an existing contact. |
name | string | Required for a new contact, at least 2 characters. |
tags | list of strings | Adds tags to the contact. |
tagsRemove | list of strings | Removes tags. Write them the way BIP stores them: lowercase, no accents, hyphens instead of spaces (lembrete-pagamento). |
fields | list of { "key", "value" } | key is the custom field name. An empty value clears the field. |
kpis | object { "id": number } | Adds to the current value. Only KPIs created in Settings. |
metadata | object | Free-form data; each key you send replaces the previous one. |
note | { "text", "createdBy" } | Adds a note to the contact. Send both fields. |
tracker | string | Links the site script visitor to the contact. |
Custom field formats: Date as yyyy-mm-dd or dd/mm/yyyy; Number with a decimal point; Boolean true or false; Location with the city name; Phone with + and the country code; Array as a JSON list.
POST /api/events fields
| Field | Type | How it works |
|---|---|---|
type | string | Required. Free-form: purchase, trial_started, nps. |
leadId | string | Contact ID. Send leadId or tracker. |
tracker | string | Visitor ID, already linked to a contact. |
value | string | Event value, such as "349.90". Required when type is click. |
metadata | object | Free-form details, such as order number and items. |
url | string | Page tied to the event. BIP stores it without https:// and without anything after ?. |
How BIP reads lead in trigger and cancel
What you send in lead | BIP looks for |
|---|---|
Text with @ | |
Text that starts with +, or digits only (7 or more) | Phone (with country code: +5511912345678) |
| Any other text | Contact ID, then visitor ID |
| Object (trigger only, via POST) | Creates or updates the contact and triggers |
Response codes
| Code | Message | What to do |
|---|---|---|
| 200 | — | It worked. |
| 400 | Validation Error | Check the data: a name with 2+ characters for a new contact, a valid email or phone, type on the event. |
| 400 | leadId or tracker is required | Identify the event's contact. |
| 400 | Campaign is not configured for API triggers | Use a campaign with API Trigger. |
| 400 | Campaign is not active | Activate the campaign with Save and Activate. |
| 403 | API key is not active / API key has expired | Turn the key on or adjust its expiration in API Keys. |
| 403 | API key does not have the required permissions | Turn on the missing scope on the key. |
| 404 | API key not found | Check that you copied the whole key. |
| 404 | Lead not found | The contact doesn't exist: create it with /api/leads or send lead as an object. |
| 404 | Campaign not found | Check the campaign ID. |
Rules that always apply
- A new contact needs a
namewith at least 2 characters and a valid email or phone. - Trigger only works on activated API Trigger campaigns.
- By default, each contact receives a campaign once. A new attempt shows up as Rejected in the stats. To repeat, turn on Allow Lead Re-entry.
- In Delay mode, each contact has at most one send waiting per campaign. A new call restarts the timer.
- On BIP Lite, each campaign trigger for a contact counts as one send for the month. Creating contacts, logging events and cancelling sends don't count.
- People who opted out don't receive the message, even when it's triggered through the API.
Ready to copy
Signed up on the site → welcome in one call
Nimbus App sends a welcome email as soon as someone creates an account. An API Trigger campaign in Immediate mode, with the welcome email, and one call with lead as an object: BIP creates the contact and sends. The Plano field (String) must exist in Settings. The key needs Campaigns Trigger and Leads Write.
curl -X POST https://api.bip.marketing/api/campaigns/trigger \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{
"campaignId": "CAMPAIGN_ID",
"lead": {
"name": "Tiago Pereira",
"email": "tiago.pereira@exemplo.com",
"tags": ["trial"],
"fields": [{ "key": "Plano", "value": "Trial" }]
}
}'// On the Nimbus App server, right after creating the user's account
const API_KEY = process.env.BIP_API_KEY ?? 'YOUR_API_KEY';
export async function enviarBoasVindas(usuario: { nome: string; email: string }) {
const res = await fetch('https://api.bip.marketing/api/campaigns/trigger', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-bip-api-key': API_KEY },
body: JSON.stringify({
campaignId: 'CAMPAIGN_ID',
lead: {
name: usuario.nome,
email: usuario.email,
tags: ['trial'],
fields: [{ key: 'Plano', value: 'Trial' }]
}
})
});
if (!res.ok) throw new Error(`BIP ${res.status}: ${await res.text()}`);
return res.json(); // { campaignId, leadId, mode }
}Purchase → purchase event
Loja Horizonte logs every paid order. First, it updates the contact with the cliente (customer) tag and adds to the receita (revenue) and pedidos (orders) KPIs (create both in Settings). Then it logs the purchase event with the amount and the order number. The key needs Leads Write and Events Write.
curl -X POST https://api.bip.marketing/api/leads \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"name": "Marina Alves", "email": "marina.alves@exemplo.com", "tags": ["cliente"], "kpis": {"receita": 349.9, "pedidos": 1}}'
curl -X POST https://api.bip.marketing/api/events \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"type": "purchase", "leadId": "CONTACT_ID", "value": "349.90", "metadata": {"pedido": "LH-10482", "itens": 3}}'// On the Loja Horizonte server, when the order payment is confirmed
const API_KEY = process.env.BIP_API_KEY ?? 'YOUR_API_KEY';
async function bip(path: string, body: unknown) {
const res = await fetch(`https://api.bip.marketing${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-bip-api-key': API_KEY },
body: JSON.stringify(body)
});
if (!res.ok) throw new Error(`BIP ${res.status}: ${await res.text()}`);
return res.json();
}
export async function registrarCompra(pedido: { id: string; total: number; itens: number; nome: string; email: string }) {
const contato = await bip('/api/leads', {
name: pedido.nome,
email: pedido.email,
tags: ['cliente'],
kpis: { receita: pedido.total, pedidos: 1 }
});
await bip('/api/events', {
type: 'purchase',
leadId: contato.id,
value: pedido.total.toFixed(2),
metadata: { pedido: pedido.id, itens: pedido.itens }
});
}With that, your customer segment takes a single criterion: KPI → Indicator Receita → Greater than or equals → the amount you want.
Cancel the reminder when they pay
Loja Horizonte reminds people who generated a Pix payment code (Brazil's instant payment method) but didn't pay. The Payment reminder campaign uses API Trigger with a Delay of 3600 seconds (one hour). The system triggers it when the Pix code is generated and cancels it when the payment comes in. If the person pays within the hour, the reminder never goes out and doesn't count as a send. The key needs Campaigns Trigger.
# Pix code generated: schedule the reminder
curl -X POST https://api.bip.marketing/api/campaigns/trigger \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"campaignId": "CAMPAIGN_ID", "lead": "marina.alves@exemplo.com"}'
# Payment confirmed: cancel the reminder
curl -X POST https://api.bip.marketing/api/campaigns/cancel \
-H "Content-Type: application/json" \
-H "x-bip-api-key: YOUR_API_KEY" \
-d '{"campaignId": "CAMPAIGN_ID", "lead": "marina.alves@exemplo.com"}'// On the Loja Horizonte server
const API_KEY = process.env.BIP_API_KEY ?? 'YOUR_API_KEY';
const CAMPANHA_LEMBRETE = 'CAMPAIGN_ID';
async function bip(path: string, body: unknown) {
const res = await fetch(`https://api.bip.marketing${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-bip-api-key': API_KEY },
body: JSON.stringify(body)
});
if (!res.ok) throw new Error(`BIP ${res.status}: ${await res.text()}`);
return res.json();
}
// Pix code generated: the reminder goes out in one hour unless something changes
export const agendarLembrete = (email: string) =>
bip('/api/campaigns/trigger', { campaignId: CAMPANHA_LEMBRETE, lead: email });
// Payment confirmed: { cancelled: true } if the reminder was still waiting
export const cancelarLembrete = (email: string) =>
bip('/api/campaigns/cancel', { campaignId: CAMPANHA_LEMBRETE, lead: email });If the buyer may not be a contact yet, swap the email in the trigger for a lead object with name and email (the key then also needs Leads Write). To remind the same person on future orders, turn on Allow Lead Re-entry in the campaign.
How to measure
- API responses: store the code and body of every response in your system.
leadId,modeandcancelledtell you what BIP did. - Contact: in Leads, open the contact. The Feed shows the creation and the updates made through the API, the tags, the KPIs and each event with its type and value. The Kpis section shows the running total.
- Source: in Segments, the First / Last Source criterion → First Source (Type) → API counts how many contacts came in through the integration.
- Campaign: in Campaigns, open View Stats for the API campaign. You see processed, delivered, opens and clicks and, under Recipient Interactions, each person's status: Sent, Rejected (already received it), Optout or Error.
Frequently asked questions
Does calling the API count as a send?
No. Creating and updating contacts and logging events don't use sends. What counts is each campaign trigger for a contact. A delayed send cancelled before it goes out doesn't count.
What happens if I trigger twice for the same person?
In Immediate mode, each call is a new trigger, and the Lead Re-entry Window decides whether the person receives it again. By default, they receive it once. In Delay mode, the second call restarts the timer and only one message goes out.
Can I call the API straight from the browser or the app?
No. The key would be visible to anyone. Call the API from your server. On your site, the site script records visits, and your server links the visitor to the contact with the tracker field.
What's the difference between the API and webhooks?
The API brings data from your system into BIP. Webhooks go the other way: they carry contact data from BIP to your system with every campaign send.