Sync members from a spreadsheet

Keep your RallyText roster in step with a registration export, a club database or a shared sheet. For a one-time upload, the dashboard's CSV import (Roster → Import) needs no code.

1. Check the numbers

POST /api/v1/recipients/validate checks up to 100 numbers at once: is each one a valid US number, is it already on your roster, and did it text STOP to your team. It changes nothing, and it doesn't call the phone carriers.

curl -X POST https://rallytext.app/api/v1/recipients/validate \
  -H "Authorization: Bearer rt_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"phones": ["(906) 555-1234", "906-555-9876", "not a number"]}'

2. Add or update each row

Try to add each person with POST /api/v1/members. A 409 member_exists response includes existing_member_id, so you can update that member with PATCH /api/v1/members/{member_id} instead. A 409 opted_out means that number texted STOP: skip it. Only the member can opt back in, by texting START to your team number.

# members.csv: name,phone,email,role with a header row and no commas inside values.
# A 409 member_exists reply includes existing_member_id: update that member with
# PATCH https://rallytext.app/api/v1/members/{existing_member_id}
tail -n +2 members.csv | while IFS=, read -r name phone email role; do
  curl -s -X POST https://rallytext.app/api/v1/members \
    -H "Authorization: Bearer rt_live_your_key_here" \
    -H "Content-Type: application/json" \
    -d "{\"name\": \"$name\", \"phone\": \"$phone\", \"email\": \"$email\", \"role\": \"${role:-athlete}\"}"
  echo
  sleep 0.6   # stay under 120 requests a minute
done

Staff (coaches, team directors, board members) and anyone with a dashboard login are managed in the dashboard, so the API returns 403 staff_member_protected for them. To store extra columns such as jersey numbers, add custom fields with POST /api/v1/custom-fields and set them with PATCH /api/v1/members/{member_id}/custom-fields. Values of a field your team marked Private can be written but are never returned.

3. Bring over your unsubscribe list

If you are moving from another texting service, record its opt-outs before your first send with POST /api/v1/opt-outs/bulk (up to 500 numbers a call). Each number is opted out on every roster entry it appears on, and a number that isn't on your roster yet is recorded too, so the API won't add it later. RallyText doesn't text these people to confirm. An opt-out is permanent through the API: only the member can undo it, by texting START. A staff member's number is refused (staff_member_protected), because staff opt out by texting STOP themselves. This works on any plan.

curl -X POST https://rallytext.app/api/v1/opt-outs/bulk \
  -H "Authorization: Bearer rt_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"items": [{"phone": "(906) 555-2222"}, {"phone": "+19065553333"}]}'

Limits

Each key gets 120 requests a minute, so the scripts above wait 0.6 seconds after each request. Bulk opt-outs, number checks, delivery reports and analytics share a separate limit of 10 calls a minute, so the opt-out script waits 6 seconds between calls. A 429 rate_limited response means slow down and retry.