meiboManage API keys

DEVELOPERS / API V1

Your workspace,
connected.

Bring enquiries into Meibo. Build tools around your records. Keep other systems up to date as your team works.

Authentication

Create a key in Settings → API keys. Send it as a Bearer token to https://app.meibolabs.com/api/v1. Keep keys on your server; never embed them in a public website or mobile bundle.

A key can access only its own workspace. Keys expire after 90 days and are revocable. Its creator must remain an owner or admin. Each key allows up to 120 requests per minute.

PermissionAccess
records:readList CRM records
records:writeCreate, update and delete records
enquiries:writeCreate website enquiries and follow-ups

Website enquiries

POST /enquiries creates a contact, an Enquiry-stage deal linked to that contact, and a task due tomorrow linked to the deal. All three records are saved together or none are saved.

Send a unique Idempotency-Key for each real submission. Reuse that key when retrying the same submission; Meibo returns the original IDs. Reusing it with different data returns 409.

curl https://app.meibolabs.com/api/v1/enquiries \
  -H "Authorization: Bearer $MEIBO_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: website-enquiry-0001' \
  -d '{
    "name": "Alex Morgan",
    "email": "alex@example.com",
    "subject": "A new partnership",
    "message": "We would love to discuss a campaign."
  }'
// 201 Created
{"data":{"contact_id":"…","deal_id":"…","task_id":"…"}}

Required fields: name (200 characters), email (254), subject (200), message (10,000). Optional owner is a Team record ID from this workspace. Without it, the deal and task belong to “Agency team”.

Connect BNOC’s website

  1. Create a key with only enquiries:write.
  2. Save it as MEIBO_API_KEY in the website’s server environment.
  3. Validate the form and apply spam protection on your website’s server.
  4. Forward the submission to this endpoint and show success only after a successful response.

Use a submission UUID for the idempotency header. Do not generate a new UUID for a retry. The repository includes a Next.js server route with Turnstile verification in examples/website-enquiry-route.ts.

Records

List records

GET /api/v1/records?kind=people&limit=50
Authorization: Bearer <key>

{"data":[{"id":"…","kind":"people","name":"Alex","status":"Active","version":1}],"next_cursor":null}

The limit is 1–100. The optional kind filters the object type. If next_cursor is present, pass it as the next request’s cursor. Results are ordered by ID; changing records during pagination is not a snapshot.

Create or update a record

POST /api/v1/records
Content-Type: application/json

{"kind":"companies","name":"Example Studio","status":"Prospect"}

// Update: send the complete record, including its current version.
{"id":"existing-id","kind":"companies","name":"Example Studio","status":"Active partner","version":1}

Creates return 201. Updates return 200 and increment the version. An outdated version returns 409. Linked fields — company, talent, owner, related, collaborators — must reference records in the same workspace. Owner and collaborators must reference Team records; “Agency team” is an unassigned owner.

Delete a record

DELETE /api/v1/records
Content-Type: application/json

{"id":"record-id","version":2}

Returns 204. Remove incoming links before deleting a record. Request bodies are limited to 30 KB and saved record data to 25 KB.

Object types and statuses

KindAllowed statuses
teamAvailable · Busy · Away
talentRepresented · In discussion · Paused
companiesActive partner · Prospect · Past partner
peopleActive · New contact · Archived
dealsEnquiry · Pitching · Negotiation · Won · Lost
campaignsBriefing · In production · In review · Delivered · Paid
tasksTo do · In progress · Done
notesNote
emailsDraft

Signed webhooks

Add a public HTTPS endpoint in Settings → Webhooks. Save the signing secret when it appears. Meibo emits record.created, record.updated, and record.deleted events after the database transaction commits.

{
  "id": "event-uuid",
  "type": "record.updated",
  "workspace_id": "workspace-uuid",
  "created_at": "2026-10-04T12:00:00.000Z",
  "data": { "id": "record-id", "kind": "deals", "version": 2 }
}

The payload identifies the change; use a read API key to retrieve current record data. Deleted records are no longer available. Delivery is at least once and order is not guaranteed. Deduplicate on the event ID.

Verify X-Meibo-Signature using HMAC SHA-256 over timestamp + "." + rawBody. Reject timestamps more than five minutes from your server clock.

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody must be the unmodified request text.
const header = request.headers.get('x-meibo-signature') ?? '';
const match = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header);
if (!match || Math.abs(Date.now() / 1000 - Number(match[1])) > 300) {
  return new Response('Invalid signature', { status: 401 });
}
const expected = createHmac('sha256', process.env.MEIBO_WEBHOOK_SECRET)
  .update(match[1] + '.' + rawBody).digest();
const supplied = Buffer.from(match[2], 'hex');
if (!timingSafeEqual(expected, supplied)) {
  return new Response('Invalid signature', { status: 401 });
}
const event = JSON.parse(rawBody);
// Persist event.id in your database with a UNIQUE constraint.
// Process each event once, even when Meibo retries delivery.
// Return 2xx only after durable acceptance.

Return a 2xx response within five seconds. Redirects are not followed. Destinations must resolve to public IPv4 addresses on HTTPS port 443. Record saves trigger delivery after the response. A scheduled worker also processes due events every five minutes, up to ten per run, with exponential backoff and a maximum of eight attempts. Check failures in Settings → Webhooks; “Send due deliveries” processes events that are ready to retry.

The default schedule is intended for the first clients. Increase worker throughput before using Meibo for a high-volume event stream.

Errors and retries

StatusWhat to do
400Check the request body and field values.
401Check the API key, expiry and revocation status.
403Check scopes and the key creator’s current permissions.
409Refresh the record version, remove blocked links, or check idempotency data.
413Reduce the request size.
415Send Content-Type: application/json.
429Wait for the Retry-After header before retrying.
503Retry later; the service or database is unavailable.
{"error":{"message":"This API key does not have the required permission.","status":403}}
Back to Meibo