- Choose one matching identity deliberately
- Select the operation for the intended change
- Separate acknowledgment from the saved record
- Keep opt-outs separate from routine profile updates
- Review a fictional withdrawn-contact payload
- Reconcile source changes before repeating work
- Frequently asked questions
- Review one contact-sync workflow
A Blackleaf contact-sync integration should choose the intended customer identity, preserve current opt-outs, and confirm the saved result separately from the request acknowledgment. A successful response is not proof that the customer record changed or that the person may receive texts.
This guide is for developers connecting a customer system to Blackleaf’s contact API. Start with the current operation reference and API developer guide. For a one-time provider change, use the broader texting data migration checklist.
The example is fictional, inert documentation and has not been executed. No contact or subscription was changed for this article. The cover is a conceptual API workflow illustration, not a contact screen or customer result.
Choose one matching identity deliberately
The reviewed POST /contact/set handler chooses one matching key in the following order. Supplying several identifiers does not make them simultaneous matching conditions.
| Order | Matching key | Integration consequence |
|---|---|---|
| 1 | A nonempty phone after accepted normalization | Phone takes precedence even when email and customerId are also supplied. |
| 2 | A nonempty email, when no usable phone remains | Email is the selected match, rather than an additional check against a phone match. |
| 3 | A nonempty customerId, when neither prior key is available | The source customer ID is a fallback matching key, not an automatic override of a supplied phone. |
The reviewed phone normalizer strips nondigits, removes a leading 1 from a longer number, and accepts a ten-digit result. This does not establish universal international-number support. Use the accepted representation consistently across writes, reads and your own crosswalk.
Keep a protected source-to-Blackleaf identity mapping. A changed phone, shared number or conflicting email needs review before a write. Adding a stable customerId does not guarantee that a request containing a new phone will update the old phone’s record or merge two profiles. The handler rejects a request with no usable matching key.
Select the operation for the intended change
Contact profile synchronization, subscription changes and messaging are separate operations. Use the method and path shown in the current reference, with workspace Bearer authentication from a trusted backend.
| Operation | Purpose | Boundary |
|---|---|---|
GET /contact/ | Read paginated contact records. | A list read is not a consistent snapshot or a completed synchronization by itself. |
GET /contact/{phone} | Read the contact selected by phone. | Use the intended workspace and accepted phone representation; confirm the returned identity. |
POST /contact/set | Submit a contact profile change. | Matching precedence and asynchronous processing require separate outcome checks. |
POST /contact/{phone}/unsubscribe | Submit an unsubscribed-state change. | Confirm the saved result and keep affected outreach held while it is unresolved. |
POST /contact/{phone}/subscribe | Submit a subscribed-state change. | Use only after the actual permission and current suppression have been reviewed. |
Keep tokens out of browser code, public examples, screenshots and customer-facing errors. Limit the integration to the profile fields it needs. The presence of rewards or balance fields in a schema does not establish the effects of a separate adjustment operation.
Separate acknowledgment from the saved record
The reviewed contact write handler returns the following acknowledgment before submitting the background contact work:
{
"success": true
}
That response does not establish that the work was queued, completed or persisted. It also does not provide a completed-contact identifier or a per-request status URL. The public operation schema’s generic id/status response example is not the same as this reviewed handler acknowledgment. Confirm the deployed representation for your integration.
Keep your own source event, record version, intended identity, submitted fields and request time. After an authorized change, compare an appropriate contact read with the intended result. Record a missing, mismatched or unavailable read as unresolved. Do not invent a fixed completion delay or treat a timeout as proof that nothing changed.
Keep opt-outs separate from routine profile updates
The public contact field is unsubscribed. The reviewed write path maps it to the stored opt-out state. The subscribe and unsubscribe routes use that same contact-write path with opposite boolean values; they do not replace a permission history.
Do not give every imported row a default unsubscribed: false. A later name, email or loyalty update must not silently reverse a newer withdrawal. Confirm how omitted, null and explicit boolean values behave in the supported workflow before enabling routine writes; omission is not a documented guarantee that every existing field remains untouched.
Retain permission evidence and withdrawal events in an approved, protected record. Reconcile the actual sender, purpose, recipient and event time before any separately authorized re-enrollment. A stored false value, purchase, source-system checkbox or successful subscribe request is not proof of valid consent.
Keep the current suppression effective in every system that can initiate affected outreach. Use the consent and withdrawal guide for the evidence review and the reply-handoff sequence to assign a staffed owner. Incoming subscription events and campaign callbacks have distinct contracts; match the receiver you actually configured.
Review a fictional withdrawn-contact payload
This JSON is a proposal to inspect against POST /contact/set, not a tested import template or an instruction to send a request. The reserved example phone, email and customer ID represent no real customer.
{
"phone": "2025550101",
"email": "sam@example.com",
"customerId": "example-customer-001",
"firstName": "Sam",
"lastName": "Rivera",
"unsubscribed": true
}
Because this payload has a usable phone, the reviewed handler matches by phone. Email and customer ID remain supplied data; they are not three-way identity verification. The explicit true value represents a withdrawal to preserve, not an instruction to reactivate the contact.
Keep birth dates and other unnecessary personal data out of public examples and diagnostic logs. Do not add undocumented fields to change permission or merge behavior. A minimal example does not establish that every other customer field is unaffected by the actual write.
Reconcile source changes before repeating work
- Record the source version. Keep the original identity and event time so an older export cannot look newer merely because it arrived later.
- Review identity and suppression first. Hold ambiguous matches, changed numbers and conflicting permission for resolution.
- Track the submitted intent. Separate the HTTP result from the expected saved profile. These are application records, not extra API request fields.
- Observe the relevant saved record. Confirm identity, intended fields and current withdrawal state through the authorized read workflow. A matching contact count alone is insufficient.
- Resolve partial or uncertain outcomes. Inspect what is already present before another write. This guide establishes no exactly-once, ordered-processing or automatic-retry guarantee.
- Keep later withdrawals current. Preserve changes received during an import, outage or recovery. Replaying an old profile must not become a re-subscription strategy.
The messaging sandbox simulates supported messaging workflows. It does not establish isolated contact writes, a copied customer dataset or a harmless environment for subscription changes. Reading this article requires no API operation.
Frequently asked questions
Does sending phone, email and customerId merge matching profiles?
No merge guarantee follows from those fields. The reviewed handler chooses phone first, then email, then customer ID. Resolve conflicting identities through the supported process before submitting changes.
Does success:true mean the contact was saved?
No. The reviewed acknowledgment is returned before background work is submitted. Confirm the intended result through the applicable contact read and keep an unresolved outcome separate from a completed update.
Does unsubscribed:false prove that the person agreed to texts?
No. Contact state is separate from the disclosure, affirmative action, sender, purpose and current withdrawal history needed for the messaging decision.
Can a profile sync safely reset subscription state from an old export?
Do not use an old profile value to reverse a newer withdrawal. Preserve event time, current suppression and any separately reviewed re-enrollment evidence.
Can I test contact writes freely on a messaging sandbox host?
Do not assume isolation. The documented messaging simulation does not make every API resource simulated or free of real effects.
Review one contact-sync workflow
Reviewed November 3, 2026 against the current public API reference, version 2.8.4, and relevant contact, subscription, response-formatting and background-processing source. Local source and public documentation do not establish a particular account’s deployed behavior. The example has not been executed.
Blackleaf requires explicit recipient consent and age confirmation before texting. In the message flow, the intended recipient selects the birthday on file; never disclose the saved birthday. Contact creation, subscription state and API access do not replace these requirements.
Bring the source identity rules, supported field mapping, permission and suppression history, expected readback and uncertain-result recovery to an API integration review. Blackleaf dispensary Texting works with supported existing POS systems without a POS switch. Confirm the actual connection and workflow before activation.