Skip to content

Canonical Flow

This is the recommended end-to-end sequence for a partner integration.

Set the base URL and API key for your target environment:

Terminal window
export MESHI_BASE="https://api.staging.meshi.io/api/v0/partner"
export MESHI_KEY="<MESHI_PARTNER_KEY>"

Use the production base URL and production key only for live traffic.

Terminal window
curl -sS "$MESHI_BASE/auth" \
-H "Authorization: Bearer $MESHI_KEY"

Continue only if the response includes partner:write in scopes.

You own event_id. Use a stable ID from your event system.

Terminal window
curl -sS -X POST "$MESHI_BASE/events" \
-H "Authorization: Bearer $MESHI_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_id": "summit-2026",
"title": "Annual Partner Summit 2026",
"description": "Two-day leadership summit",
"start_date": "2026-09-10",
"end_date": "2026-09-11",
"timezone": "America/New_York",
"visibility": "private",
"url_slug": "summit-2026"
}'

201 means the event was created. 409 PARTNER_ID_CONFLICT means that ID already exists in your org; fetch the event and continue if it is the same logical event.

Context helps downstream matching use event-specific goals and instructions. Send at least one field.

Terminal window
curl -sS -X POST "$MESHI_BASE/events/summit-2026/context" \
-H "Authorization: Bearer $MESHI_KEY" \
-H "Content-Type: application/json" \
-d '{
"event_details": "Senior product and engineering leaders from portfolio companies.",
"objectives": "Maximize useful cross-company introductions.",
"welcome_instructions": "Introduce yourself with your top goal for the summit."
}'

Each context field is optional, but at least one must be present. Each value is capped at 4000 characters.

Imports are async. Each attendee needs a stable attendee_id and name; email, LinkedIn URL, title, company, and raw data are optional.

Terminal window
IDEMP=$(uuidgen)
curl -sS -X PUT "$MESHI_BASE/events/summit-2026/attendees:import" \
-H "Authorization: Bearer $MESHI_KEY" \
-H "Content-Type: application/json" \
-d "{
\"idempotency_key\": \"$IDEMP\",
\"attendees\": [
{
\"attendee_id\": \"att-1001\",
\"name\": \"Jordan Lee\",
\"email\": \"jordan@example.com\",
\"linkedin_url\": \"https://www.linkedin.com/in/jordanlee\",
\"title\": \"VP Product\",
\"company\": \"Acme\",
\"raw_data\": { \"source\": \"crm-export-2026-06\" }
},
{
\"attendee_id\": \"att-1002\",
\"name\": \"Sam Rivera\",
\"title\": \"Head of Partnerships\",
\"company\": \"Globex\"
}
]
}"

The first accepted call returns 202 with kind: "import" and idempotent_replay: false. A replay with the same idempotency key and event returns 200 with idempotent_replay: true.

Poll GET /runs/:run_id until status is terminal: succeeded, partial, or failed.

Terminal window
poll_run () {
local run_id="$1"
local delay=2
local max=30
while :; do
resp=$(curl -sS "$MESHI_BASE/runs/$run_id" \
-H "Authorization: Bearer $MESHI_KEY")
status=$(echo "$resp" | jq -r '.status')
case "$status" in
succeeded|partial|failed)
echo "$resp"
return 0
;;
*)
sleep "$delay"
if [ "$delay" -lt "$max" ]; then delay=$((delay * 2)); fi
if [ "$delay" -gt "$max" ]; then delay="$max"; fi
;;
esac
done
}
poll_run "<IMPORT_RUN_ID>"

For partial or failed, inspect progress and error.

Terminal window
IDEMP=$(uuidgen)
curl -sS -X POST "$MESHI_BASE/events/summit-2026/enrichment-runs" \
-H "Authorization: Bearer $MESHI_KEY" \
-H "Content-Type: application/json" \
-d "{ \"idempotency_key\": \"$IDEMP\" }"

The response includes a queued run. Poll it to terminal with the same poll_run function.

Example enrichment progress:

{
"total": 2,
"processed": 2,
"enrichment_requested": 2,
"review_required": 0,
"skipped": 0,
"error_count": 0,
"errors": []
}

Rows with REVIEW_REQUIRED need identity review resolution. Rows with NO_SOURCE_RECORD had no source record available for enrichment.

Terminal window
IDEMP=$(uuidgen)
curl -sS -X POST "$MESHI_BASE/events/summit-2026/match-runs" \
-H "Authorization: Bearer $MESHI_KEY" \
-H "Content-Type: application/json" \
-d "{ \"idempotency_key\": \"$IDEMP\", \"top_n\": 10 }"

top_n is optional, defaults to 10, and must be between 1 and 50. Poll the returned match run to terminal.

Read all matches for the event:

Terminal window
curl -sS "$MESHI_BASE/events/summit-2026/matches?limit=50" \
-H "Authorization: Bearer $MESHI_KEY"

Read top matches for one attendee:

Terminal window
curl -sS "$MESHI_BASE/events/summit-2026/attendees/att-1001/matches?limit=10" \
-H "Authorization: Bearer $MESHI_KEY"

Read one ordered pair:

Terminal window
curl -sS "$MESHI_BASE/events/summit-2026/matches/att-1001/att-1002" \
-H "Authorization: Bearer $MESHI_KEY"

Match lists are ordered descending by final_score.

List open reviews:

Terminal window
curl -sS "$MESHI_BASE/review-queue?limit=50" \
-H "Authorization: Bearer $MESHI_KEY"

Resolve a review:

Terminal window
curl -sS -X POST "$MESHI_BASE/review-queue/<REVIEW_ID>/resolve" \
-H "Authorization: Bearer $MESHI_KEY" \
-H "Content-Type: application/json" \
-d '{ "decision": "accept", "reason": "Confirmed by source system operator." }'

Valid decisions are accept, reject, and distinct.

  • Use the production base URL and production key.
  • Log every correlation_id.
  • Generate one idempotency key per logical write operation, and reuse it only for retries of that same operation.
  • Poll async runs to terminal; do not wait for webhook delivery in v0.
  • Page through next_cursor verbatim until it is null.
  • On 429, honor the Retry-After header before retrying.