API reference
Compliance / CASL
CASL consent and opt-out management.
/v1/compliance/consentsList consent records for account's subscribers
compliance:rNode.js SDKhonkio.consents.list()Consents and opt-outs are kept per key mode: a test key records, reads and changes its own (test) records, which only test sends are checked against, and a live key the live ones.
Requires compliance:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
phone_numberquery | string | |
email_addressquery | string | Filter to the email consents for this address. Email consent is available when the email product launches. |
statusquery | string |
|
consent_batch_idquery | string | Only the consents recorded by this bulk upload.
|
pagequery | integer |
|
limitquery | integer |
|
Responses
200A page of consent records, newest first. No total is returned.
Field Type Description data[]requiredobject[] idrequiredstring accountIdrequiredstring channelrequiredstring - One of: SMS | EMAIL
phoneNumberrequiredstring - Can be null
emailAddressrequiredstring - Can be null
consentTyperequiredstring - One of: EXPRESS | IMPLIED
statusrequiredstring - One of: ACTIVE | EXPIRED | REVOKED
sourceDescriptionrequiredstring - Can be null
sourceIprequiredstring - Can be null
sourceUrlrequiredstring - Can be null
relationshipTyperequiredstring - Can be null
expiresAtrequiredstring - Format: date-time
- Can be null
grantedAtrequiredstring - Format: date-time
revokedAtrequiredstring - Format: date-time
- Can be null
revokedReasonrequiredstring - Can be null
doubleOptInConfirmedAtrequiredstring When the subscriber last confirmed double opt-in by replying YES to an opt-in confirmation from one of your toll-free numbers. A toll-free send needs a confirmation from its own sending number: see GET /v1/compliance/opt-in-confirmations.
- Format: date-time
- Can be null
doubleOptInConfirmationIdrequiredstring The opt-in confirmation (oic_…) they answered.
- Can be null
consentBatchIdrequiredstring The bulk upload (cb_…) that recorded this consent; null for one recorded on its own.
- Can be null
moderequiredstring The mode of the key that recorded it. A test key sees TEST records only, a live key LIVE ones.
- One of: LIVE | TEST
livemoderequiredboolean false for a record made or read with a test key (a test-mode record), true for a live one.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422VALIDATION_ERROR: the request failed validation; details names the fields.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
- 501EMAIL_COMING_SOON: email consent is available when the email product launches (sent only for an email_address request).The standard error body.
Example
const { data, error } = await honkio.consents.list({ status: 'ACTIVE', limit: 50 })
if (error) throw new Error(error.message)
console.log(data.data.length)curl https://api.honkio.ca/v1/compliance/consents \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/consentsRecord CASL consent for a phone number or email address
compliance:wNode.js SDKhonkio.consents.create()Records express or implied consent per CASL §6-10. Every SMS needs consent on file for its recipient, transactional or commercial (a verification code through the Verify API needs none); email needs it only for commercial sends. Refused with 409 CONSENT_REVOKED_BY_REVIEW when HonkIO revoked this recipient's consent on review of a bulk upload: such consent cannot be recorded again unless HonkIO lifts the block. Consents and opt-outs are kept per key mode: a test key records, reads and changes its own (test) records, which only test sends are checked against, and a live key the live ones.
Requires compliance:w.
Request body
| Field | Type | Description |
|---|---|---|
phone_number | string | E.164 phone number of subscriber |
email_address | string | Email address of the subscriber (email channel). Email consent is available when the email product launches.
|
consent_typerequired | string |
|
source_description | string | How/where consent was obtained (required for express)
|
source_ip | string | IP address of subscriber at time of consent
|
source_url | string | URL where consent was obtained
|
relationship_type | string | Business relationship type (required for implied; e.g. "purchase", "inquiry", "member"). It sets how long implied consent lasts (CASL s. 10(10), 10(13)): 2 years for a purchase, lease, contract, business opportunity, donation, volunteer work or membership; 6 months for an inquiry or application, and for any type that names neither.
|
last_transaction_date | string | Date of last transaction (implied consent: the 2-year or 6-month expiry runs from this; today when absent)
|
expires_at | string | Explicit expiry (ISO 8601 date or date-time) for implied consent. Overrides the expiry derived from last_transaction_date. Not accepted for express consent, which never expires (CASL §10). |
Responses
201Default Response
Field Type Description statusstring phone_numberstring email_addressstring expires_atstring When this consent lapses (implied only); null for express consent.
- Can be null
livemodeboolean false for a record made or read with a test key (a test-mode record), true for a live one.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 409CONSENT_REVOKED_BY_REVIEW: HonkIO revoked this recipient's consent on review of a bulk upload, so it cannot be recorded again unless HonkIO lifts the block.The standard error body.
- 422INVALID_PHONE_NUMBER, EMAIL_INVALID_ADDRESS, or VALIDATION_ERROR (provide exactly one of phone_number or email_address; express consent needs source_description and takes no expires_at; implied consent needs relationship_type).The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
- 501EMAIL_COMING_SOON: email consent is available when the email product launches (sent only for an email_address request).The standard error body.
Example
const { error } = await honkio.consents.create({
phoneNumber: '+1613XXXXXXX',
consentType: 'express',
sourceDescription: 'Website opt-in form',
})
if (error) throw new Error(error.message)curl -X POST https://api.honkio.ca/v1/compliance/consents \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+1613XXXXXXX",
"consent_type": "express",
"source_description": "Website opt-in form"
}'/v1/compliance/consents/batchRecord CASL consent for up to 5,000 phone numbers
compliance:wNode.js SDKhonkio.consents.recordBatch()Each row is defaults with the row's own fields on top. Every row gets its own outcome: recorded, invalid, duplicate_in_file (the number appeared on an earlier row), opted_out (the number has opted out; never re-consented by an upload), revoked_by_review (HonkIO revoked the number's consent on review of an earlier upload; it cannot be recorded again unless HonkIO lifts the block) or already_recorded (an active consent at least as strong exists, so re-sending a file records nothing twice). The upload is kept as a consent batch (GET /v1/compliance/consent-batches). SMS only. A test key's upload records test consents, judged against its own (test) opt-outs and consents.
Requires compliance:w.
Request body
| Field | Type | Description |
|---|---|---|
defaultsrequired | object | The fields every row starts from. |
consent_typerequired | string |
|
source_description | string |
|
source_ip | string |
|
source_url | string |
|
relationship_type | string |
|
last_transaction_date | string |
|
expires_at | string |
|
rows[]required | object[] | 1 to 5,000 rows; each row's fields override the defaults. |
phone_numberrequired | string |
|
consent_type | string | express or implied; any other value makes that row invalid.
|
source_description | string |
|
source_ip | string |
|
source_url | string |
|
relationship_type | string |
|
last_transaction_date | string |
|
expires_at | string |
|
file_name | string | The uploaded file's name, kept on the batch.
|
attested | boolean | The uploader confirms these people gave this consent or have this relationship. Recorded on the batch. |
Responses
200Every row's outcome, in the order sent, and the counts. Partial success is normal: only a request that is wrong as a whole is refused.
Field Type Description batch_idrequiredstring cb_…
livemoderequiredboolean false for a record made or read with a test key (a test-mode record), true for a live one.
countsrequiredobject rowsrequiredinteger recordedrequiredinteger expressrequiredinteger impliedrequiredinteger already_recordedrequiredinteger opted_outrequiredinteger revoked_by_reviewrequiredinteger duplicate_in_filerequiredinteger invalidrequiredinteger results[]requiredobject[] rowrequiredinteger Index into rows.
phone_numberrequiredstring E.164, or the input as sent when it did not parse.
statusrequiredstring - One of: recorded | invalid | duplicate_in_file | opted_out | revoked_by_review | already_recorded
reasonstring Present on invalid rows (the field and what is wrong with it) and on revoked_by_review rows.
consent_typestring Present on recorded rows.
- One of: express | implied
expires_atstring Present on recorded rows; null for express.
- Can be null
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422VALIDATION_ERROR: rows empty or over 5,000, or defaults wrong in themselves (unknown consent_type, an unparseable date, expires_at with express).The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.consents.recordBatch({
defaults: { consentType: 'implied', relationshipType: 'volunteer', lastTransactionDate: '2026-05-01' },
rows: [{ phoneNumber: '+1613XXXXXXX' }],
fileName: 'volunteers.csv',
})
if (error) throw new Error(error.message)
console.log(data.counts)curl -X POST https://api.honkio.ca/v1/compliance/consents/batch \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"defaults": {
"consent_type": "express"
},
"rows": [
{
"phone_number": "+1613XXXXXXX"
}
]
}'/v1/compliance/consent-batchesList bulk consent uploads
compliance:rNode.js SDKhonkio.consentBatches.list()Requires compliance:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
pagequery | integer |
|
limitquery | integer |
|
Responses
200A page of bulk uploads, newest first. No total is returned.
Field Type Description data[]requiredobject[] idrequiredstring cb_…
livemoderequiredboolean false for a record made or read with a test key (a test-mode record), true for a live one.
sourcerequiredstring Sent through the API, or uploaded on the dashboard.
- One of: api | dashboard
file_namerequiredstring The file name the uploader gave, if any.
- Can be null
attestedrequiredboolean Whether the uploader confirmed these people gave this consent or have this relationship.
countsrequiredobject rowsrequiredinteger recordedrequiredinteger expressrequiredinteger impliedrequiredinteger already_recordedrequiredinteger opted_outrequiredinteger revoked_by_reviewrequiredinteger duplicate_in_filerequiredinteger invalidrequiredinteger revoked_atrequiredstring - Format: date-time
- Can be null
created_atrequiredstring - Format: date-time
defaultsobject The defaults the upload was sent with, as sent. Only on GET /v1/compliance/consent-batches/{id}.
consent_typerequiredstring - One of: express | implied
source_descriptionstring source_ipstring source_urlstring relationship_typestring last_transaction_datestring expires_atstring - Can be null
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422VALIDATION_ERROR: the request failed validation; details names the fields.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.consentBatches.list()
if (error) throw new Error(error.message)
console.log(data.data.length)curl https://api.honkio.ca/v1/compliance/consent-batches \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/consent-batches/{id}Get a bulk consent upload
compliance:rNode.js SDKhonkio.consentBatches.get()Requires compliance:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
|
Responses
200The upload, with the defaults it was sent with.
Field Type Description idrequiredstring cb_…
livemoderequiredboolean false for a record made or read with a test key (a test-mode record), true for a live one.
sourcerequiredstring Sent through the API, or uploaded on the dashboard.
- One of: api | dashboard
file_namerequiredstring The file name the uploader gave, if any.
- Can be null
attestedrequiredboolean Whether the uploader confirmed these people gave this consent or have this relationship.
countsrequiredobject rowsrequiredinteger recordedrequiredinteger expressrequiredinteger impliedrequiredinteger already_recordedrequiredinteger opted_outrequiredinteger revoked_by_reviewrequiredinteger duplicate_in_filerequiredinteger invalidrequiredinteger revoked_atrequiredstring - Format: date-time
- Can be null
created_atrequiredstring - Format: date-time
defaultsobject The defaults the upload was sent with, as sent. Only on GET /v1/compliance/consent-batches/{id}.
consent_typerequiredstring - One of: express | implied
source_descriptionstring source_ipstring source_urlstring relationship_typestring last_transaction_datestring expires_atstring - Can be null
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404NOT_FOUND: no such resource on this account.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.consentBatches.get('BATCH_ID')
if (error) throw new Error(error.message)
console.log(data.counts)curl https://api.honkio.ca/v1/compliance/consent-batches/ID \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/consents/checkCheck if a phone number or email address has valid CASL consent
compliance:rNode.js SDKhonkio.consents.check()A consent this check finds past its expiry is marked EXPIRED as a side effect of the check itself, not only by a background job: this call can write, not just read. It answers for the calling key's mode: a test key checks the test records a test send would be checked against, a live key the live ones.
Requires compliance:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
phone_numberquery | string | |
email_addressquery | string | Check an email address instead of a phone number. Email consent is available when the email product launches. |
Responses
200Whether a send to the phone number or email address would pass the CASL gate. Exactly one of phone_number/email_address is present, matching the subject queried. consentType and reason are camelCase and mutually exclusive.
Field Type Description phone_numberstring email_addressstring allowedrequiredboolean consentTypestring Present when allowed.
- One of: EXPRESS | IMPLIED
reasonstring Present when not allowed.
- One of: OPT_OUT | NO_CONSENT | CONSENT_EXPIRED
livemodeboolean false for a record made or read with a test key (a test-mode record), true for a live one.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422INVALID_PHONE_NUMBER, EMAIL_INVALID_ADDRESS, or VALIDATION_ERROR (provide exactly one of phone_number or email_address).The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
- 501EMAIL_COMING_SOON: email consent is available when the email product launches (sent only for an email_address request).The standard error body.
Example
const { data, error } = await honkio.consents.check({ phoneNumber: '+1613XXXXXXX' })
if (error) throw new Error(error.message)
console.log(data.allowed, data.reason)curl https://api.honkio.ca/v1/compliance/consents/check \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/consents/{phone}Revoke CASL consent for a phone number
compliance:mdNode.js SDKhonkio.consents.revoke()Revokes consent records for the given number. Every SMS to it is then refused with NO_CONSENT until consent is recorded again. Opt-outs are separate: an opt-out (POST /opt-outs) blocks sends even when consent is on file, and only the recipient can lift it. A test key revokes test consents only, and a live key live ones.
Requires compliance:m or compliance:d (any of).
Parameters
| Parameter | Type | Description |
|---|---|---|
phonerequiredpath | string |
Responses
- 204Every active consent for the number is revoked.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404NOT_FOUND: no active consent for the number.The standard error body.
- 422INVALID_PHONE_NUMBER.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { error } = await honkio.consents.revoke({ phoneNumber: '+1613XXXXXXX' })
if (error) throw new Error(error.message)curl -X DELETE https://api.honkio.ca/v1/compliance/consents/PHONE \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/consents/email/{address}Revoke CASL consent for an email address
compliance:mdNode.js SDKhonkio.consents.revoke()Revokes the ACTIVE email consents for the address. Commercial email to it is then refused with EMAIL_NO_CONSENT until consent is recorded again; transactional email is unaffected. Opt-outs and suppressions are separate.
Requires compliance:m or compliance:d (any of).
Parameters
| Parameter | Type | Description |
|---|---|---|
addressrequiredpath | string |
Responses
- 204Every active consent for the email address is revoked.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404NOT_FOUND: no active consent for the email address.The standard error body.
- 422EMAIL_INVALID_ADDRESS.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
- 501EMAIL_COMING_SOON: email consent is available when the email product launches.The standard error body.
Example
const { error } = await honkio.consents.revoke({ emailAddress: 'sam@example.com' })
if (error) throw new Error(error.message)curl -X DELETE https://api.honkio.ca/v1/compliance/consents/email/ADDRESS \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/opt-outsList opt-out records
compliance:rConsents and opt-outs are kept per key mode: a test key records, reads and changes its own (test) records, which only test sends are checked against, and a live key the live ones.
Requires compliance:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
phone_numberquery | string | |
from_numberquery | string | |
pagequery | integer |
|
limitquery | integer |
|
Responses
200A page of opt-out records, newest first. No total is returned.
Field Type Description data[]requiredobject[] idrequiredstring accountIdrequiredstring channelrequiredstring - One of: SMS | EMAIL
phoneNumberrequiredstring - Can be null
fromNumberrequiredstring The sending number the subscriber opted out from (SMS).
- Can be null
fromAddressrequiredstring - Can be null
emailAddressrequiredstring - Can be null
keywordUsedrequiredstring STOP, UNSUBSCRIBE and so on; null for an opt-out recorded through the API.
- Can be null
optedOutAtrequiredstring - Format: date-time
reinstatedAtrequiredstring - Format: date-time
- Can be null
reinstateKeywordrequiredstring - Can be null
moderequiredstring LIVE for a STOP to one of your numbers, an unsubscribe from a live email, or one a live key recorded; TEST for one a test key recorded or a test email produced. A test key sees TEST records only, a live key LIVE ones.
- One of: LIVE | TEST
livemoderequiredboolean false for a record made or read with a test key (a test-mode record), true for a live one.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422VALIDATION_ERROR: the request failed validation; details names the fields.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
curl https://api.honkio.ca/v1/compliance/opt-outs \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/opt-outsManually record an opt-out for a phone number
compliance:wConsents and opt-outs are kept per key mode: a test key records, reads and changes its own (test) records, which only test sends are checked against, and a live key the live ones.
Requires compliance:w.
Request body
| Field | Type | Description |
|---|---|---|
phone_numberrequired | string | Number that is opting out (subscriber) |
from_numberrequired | string | Your sending number they are opting out from |
Responses
201Opted out.
Field Type Description statusrequiredstring - One of: opted_out
livemoderequiredboolean false for a record made or read with a test key (a test-mode record), true for a live one.
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403PHONE_NUMBER_NOT_OWNED: a live key recorded an opt-out from a number the account does not hold.The standard error body.
- 422INVALID_PHONE_NUMBER or VALIDATION_ERROR.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
curl -X POST https://api.honkio.ca/v1/compliance/opt-outs \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+1613XXXXXXX",
"from_number": "+1416XXXXXXX"
}'/v1/compliance/opt-in-confirmationsList double opt-in confirmations
compliance:rNode.js SDKhonkio.optInConfirmations.list()Newest first. A pending confirmation past its 7 days is reported EXPIRED. Confirmations are live only, so a test key lists none.
Requires compliance:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
toquery | string | Only confirmations sent to this recipient (E.164). |
statusquery | string |
|
pagequery | integer |
|
limitquery | integer |
|
Responses
200A page of confirmations, newest first. No total is returned. Empty for a test key.
Field Type Description data[]requiredobject[] idrequiredstring oic_…
statusrequiredstring PENDING until the recipient replies YES (CONFIRMED), it lapses after 7 days or is replaced by a newer one (EXPIRED), or the recipient texts STOP (DECLINED).
- One of: PENDING | CONFIRMED | EXPIRED | DECLINED
fromrequiredstring The toll-free number it was sent from.
- Can be null
torequiredstring The recipient.
brand_namerequiredstring languagerequiredstring - One of: en | fr
message_idrequiredstring The confirmation text, as a message (GET /v1/messages/{id}).
- Can be null
expires_atrequiredstring - Format: date-time
confirmed_atrequiredstring - Format: date-time
- Can be null
reply_message_idrequiredstring The recipient's YES, as an inbound message.
- Can be null
created_atrequiredstring - Format: date-time
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422INVALID_PHONE_NUMBER (the to filter) or VALIDATION_ERROR.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.optInConfirmations.list({ to: '+1613XXXXXXX' })
if (error) throw new Error(error.message)
for (const c of data.data) console.log(c.id, c.status)curl https://api.honkio.ca/v1/compliance/opt-in-confirmations \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/compliance/opt-in-confirmationsSend a double opt-in confirmation from a toll-free number
compliance:wNode.js SDKhonkio.optInConfirmations.send()Texts the recipient a fixed confirmation from your verified toll-free number: "{brand_name}: reply YES to confirm you want text messages from us. Msg & data rates may apply. Reply STOP to opt out." (with language: "fr": "{brand_name} : répondez OUI pour confirmer que vous voulez recevoir nos textos. Des frais de messagerie et de données peuvent s’appliquer. Répondez ARRET pour vous désabonner.").
Canadian toll-free messaging needs double opt-in, per sending number: until the recipient replies YES, Y, OUI or O to this number, sends to them from it are refused with 451 DOUBLE_OPT_IN_REQUIRED (each of your toll-free numbers asks for its own). The reply confirms the confirmation, records the double opt-in for this number, and fires consent.double_opt_in_confirmed. A STOP to this number withdraws it. Verification codes (POST /v1/verify) are exempt.
The recipient must already have an active consent (the first opt-in). The confirmation is billed as a normal message and expires after 7 days. Sending another from the same number replaces the pending one; at most 3 can be sent to one recipient in 24 hours, from any of your numbers. Live keys only.
Requires compliance:w.
Request body
| Field | Type | Description |
|---|---|---|
fromrequired | string | Your toll-free number (E.164) with an approved toll-free verification. |
torequired | string | The recipient (E.164, Canadian), who must already have an active consent. |
brand_namerequired | string | The name the recipient knows you by, shown at the start of the text. Plain text: letters, numbers, spaces and . , ' & ! -, not a link.
|
language | string | The language of the confirmation text.
|
Responses
201Sent: the confirmation, PENDING until the recipient replies YES.
Field Type Description idrequiredstring oic_…
statusrequiredstring PENDING until the recipient replies YES (CONFIRMED), it lapses after 7 days or is replaced by a newer one (EXPIRED), or the recipient texts STOP (DECLINED).
- One of: PENDING | CONFIRMED | EXPIRED | DECLINED
fromrequiredstring The toll-free number it was sent from.
- Can be null
torequiredstring The recipient.
brand_namerequiredstring languagerequiredstring - One of: en | fr
message_idrequiredstring The confirmation text, as a message (GET /v1/messages/{id}).
- Can be null
expires_atrequiredstring - Format: date-time
confirmed_atrequiredstring - Format: date-time
- Can be null
reply_message_idrequiredstring The recipient's YES, as an inbound message.
- Can be null
created_atrequiredstring - Format: date-time
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402INSUFFICIENT_BALANCE: the balance cannot cover the send. RENT_OWED: rent is owed on a number released while suspended; top up to pay it first. Also PAYMENT_REQUIRED when a LIVE key is used before the first top-up.The standard error body.
- 403TOLL_FREE_NOT_VERIFIED (from has no approved toll-free verification), ACCOUNT_NOT_VERIFIED, LIVE_KEY_REQUIRED (test keys cannot send one), ALLOW_LIST_BLOCKED, DENY_LIST_BLOCKED or SENDING_PAUSED. Also FORBIDDEN when the key lacks compliance:w.The standard error body.
- 409PHONE_NUMBER_SUSPENDED: the from number is suspended for unpaid rent.The standard error body.
- 422INVALID_PHONE_NUMBER, NOT_A_TOLL_FREE_NUMBER (from is not one of your toll-free numbers), VALIDATION_ERROR (brand_name must be plain text, not a link), NON_CANADIAN_NUMBER, RESERVED_DESTINATION, UNDELIVERABLE_NUMBER or NOT_A_MOBILE_NUMBER. A refused send costs nothing.The standard error body.
- 429OPT_IN_CONFIRMATION_LIMIT (3 to one recipient in 24 hours), DAILY_LIMIT_REACHED, FANOUT_LIMIT_REACHED, NUMBER_RATE_LIMITED or RECIPIENT_RATE_LIMITED (Retry-After set on the two rate limits), or RATE_LIMITED at 100 requests per second.The standard error body.
- 451The recipient has no first opt-in: NO_CONSENT, CONSENT_EXPIRED or OPT_OUT_BLOCKED.The standard error body.
- 500Unexpected server error.The standard error body.
- 502CARRIER_ERROR: the carrier refused the send. Any charge is refunded and no confirmation is kept.The standard error body.
- 503CARRIER_UNAVAILABLE, CARRIER_THROTTLED or CARRIER_TIMEOUT: see POST /v1/messages. No confirmation is kept; send again.The standard error body.
Example
const { data: confirmation, error } = await honkio.optInConfirmations.send({
from: '+1833XXXXXXX', // your verified toll-free number
to: '+1613XXXXXXX',
brandName: 'Acme Clinics',
})
if (error) throw new Error(`${error.name}: ${error.message}`)
console.log(confirmation.id, confirmation.status) // 'PENDING' until they reply YEScurl -X POST https://api.honkio.ca/v1/compliance/opt-in-confirmations \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+1416XXXXXXX",
"to": "+1613XXXXXXX",
"brand_name": "..."
}'
HonkIO