Browse the docs

Guide 03

Push to a sequence or CRM

Send table rows to contacts, an existing sequence or HubSpot, with review before anything goes out.

Last updated from API version 2026-10-06 at (live spec, refreshed hourly). openapi.json

POST /tables/{id}/rows/push moves table rows on: to contacts, to an existing sequence, to a crm (HubSpot), or through a send column. Pushing to contacts is free and immediate. The other targets contact people or write to your CRM, so they are one action with a dry run, a plan and a person's approval.

1. Rows to contacts

Up to 200 rows per request, by rowIds or by filter with confirmCount (the number of rows you expect it to match). Each row is matched to a contact by its linked contact, then LinkedIn URL, then email; a match gets its empty fields filled (onConflict: "fillEmpty"), otherwise a contact is created and linked to the row.

bash
curl -X POST "https://app.owlbound.ai/api/v1/tables/$TABLE_ID/rows/push" \
  -H "Authorization: Bearer $OWLBOUND_API_KEY" \
  -H "Owlbound-Version: 2026-10-06" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "target": "contacts",
  "filter": {
    "column": "workEmail",
    "op": "notEmpty"
  },
  "confirmCount": 143,
  "dryRun": true
}'

Drop dryRun to write. Rows without a valid email or LinkedIn URL are skipped.

2. Rows to a sequence

target: "sequence" with a sequenceId enrolls each row's linked contact through actions.sequences.enroll (4 credits per target). It needs act as well as write, an Idempotency-Key and rowIds (at most 200). Dry run first:

bash
curl -X POST "https://app.owlbound.ai/api/v1/tables/$TABLE_ID/rows/push" \
  -H "Authorization: Bearer $OWLBOUND_API_KEY" \
  -H "Owlbound-Version: 2026-10-06" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "target": "sequence",
  "sequenceId": "<sequenceId>",
  "rowIds": [
    "<rowId>"
  ],
  "dryRun": true
}'

The plan lists who would be enrolled and who skipped (SUPPRESSED, UNSUBSCRIBED, EXCLUDED, IN_SEQUENCE, ALREADY_ENROLLED, NO_CONTACT, ...). Apply it with its planId: the answer is 202 with an action in pending_approval. The sequence's identity owner approves it in the app, then the sequence sends with its own limits, working hours and guards.

3. Rows to HubSpot

target: "crm" with crm: {provider: "hubspot", object: "contact" | "company"}upserts each linked contact (or its company) with the workspace's own HubSpot connection. Records are looked up first; an existing record only gets its empty fields filled, a different CRM value is kept and counted as a conflict, and nothing is ever cleared or deleted. CRM writes are free.

bash
curl -X POST "https://app.owlbound.ai/api/v1/tables/$TABLE_ID/rows/push" \
  -H "Authorization: Bearer $OWLBOUND_API_KEY" \
  -H "Owlbound-Version: 2026-10-06" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "target": "crm",
  "crm": {
    "provider": "hubspot",
    "object": "contact"
  },
  "rowIds": [
    "<rowId>"
  ],
  "dryRun": true
}'

4. A send column

An action column whose operation is actions.linkedin.connect, .dm, .inmail or actions.sequences.enroll is a send column. target: "column" with its columnIdcreates one action over the rows, each row's input resolved from its cells ({{Column}}) and frozen at approval. A row whose last run of the column is pending, running or sent is skipped ALREADY_RUN: a row is never sent twice by its column.

Without a table

The same actions take contacts, rows or a saved view as targets directly: POST /actions/sequences/enroll, POST /actions/crm/hubspot/upsert_contact and POST /actions/crm/hubspot/upsert_company. See approvals and never-twice for what happens after you apply.