Skip to main content

Channels API

A channel is a configured delivery endpoint owned by your workspace — an iOS app, an Android app, a web-push origin, an email sender, or an in-app surface. Each channel carries provider credentials (uploaded separately, see Credentials) and a verification status that reflects whether those credentials have been validated against the provider.

These endpoints are authenticated with a bearer token:

Authorization: Bearer YOUR_ACCESS_TOKEN

The channel object

FieldTypeDescription
idstringChannel UUID.
typestringOne of ios, android, web_push, email, in_app, sms (Beta), whatsapp (Beta).
namestringDisplay name, unique per workspace.
activebooleanWhether the channel is enabled for sending.
statusstringCredential verification state: pending, active, or invalid.
verified_atstringRFC 3339 timestamp of the last successful verification. Omitted until verified.
verification_errorstringProvider error from the last failed verification. Omitted when there is none.
created_atstringCreation timestamp.

A channel starts in status: "pending". Uploading credentials queues an asynchronous verification against the provider; on success the channel moves to active, on failure to invalid with verification_error populated. Re-uploading credentials or calling the verify endpoint resets the cycle.


POST /api/v1/channels

Creates a channel.

Request Body

{
"type": "ios",
"name": "My iOS App"
}
FieldTypeRequiredDescription
typestringYesOne of ios, android, web_push, email, in_app. SMS and WhatsApp channels are provisioned as part of the Beta and cannot yet be created through this endpoint.
namestringYesDisplay name, up to 128 characters.

Response — 201 Created

{
"id": "6f1d2a34-9c1b-4e8a-b0d2-1a2b3c4d5e6f",
"type": "ios",
"name": "My iOS App",
"active": true,
"status": "pending",
"created_at": "2026-07-27T12:00:00Z"
}

Error responses

StatusMeaning
401Missing or invalid bearer token
403Channel type not included in your plan. The body carries "upgrade_required": true and an allowed list of the channel types your plan permits.
422Validation failure (unknown type, missing or over-long name)

GET /api/v1/channels

Lists all channels in the workspace.

Response — 200 OK

{
"channels": [
{
"id": "6f1d2a34-9c1b-4e8a-b0d2-1a2b3c4d5e6f",
"type": "ios",
"name": "My iOS App",
"active": true,
"status": "active",
"verified_at": "2026-07-27T12:05:00Z",
"created_at": "2026-07-27T12:00:00Z"
}
]
}

GET /api/v1/channels/:id

Fetches a single channel by UUID.

Returns 200 with the channel object, or 404 if no channel with that ID exists in the workspace.

PATCH /api/v1/channels/:id

Updates a channel. Both fields are optional; omitted fields are unchanged.

Request Body

{
"name": "Renamed App",
"active": false
}
FieldTypeRequiredDescription
namestringNoNew display name.
activebooleanNoEnable or disable the channel for sending.

Response — 200 OK

The updated channel object.

DELETE /api/v1/channels/:id

Deletes a channel.

Query parameters

ParamTypeDescription
forcebooleanWhen true, deletes the channel even if it has credentials stored.

Response

204 No Content on success.

StatusMeaning
404Channel not found
409Channel has credentials stored and force=true was not supplied

POST /api/v1/channels/:id/verify

Re-queues credential verification for the channel. Use this after fixing a provider-side problem (revoked key, changed bundle ID) without re-uploading the credentials.

Response — 202 Accepted

{ "status": "queued" }

Returns 404 if the channel has no credentials stored. Poll GET /api/v1/channels/:id to observe the resulting status transition.


Credentials

Provider credentials are write-only secrets. They are encrypted with a KMS-managed key at rest and are never returned by any API — the upload response confirms only the credential's metadata (id, channel_id, type, timestamps). If you lose a credential, upload a new one; there is no way to read it back.

Uploading credentials to a channel that already has some replaces them and re-queues verification.

POST /api/v1/channels/:id/credentials/apns

Uploads an APNs token-signing key for an ios channel. The request is multipart/form-data.

Form fields

FieldTypeRequiredDescription
key_filefileYesThe .p8 APNs auth key file from your Apple Developer account.
key_idstringNoThe 10-character Key ID of the .p8 key.
team_idstringNoYour Apple Developer Team ID.
bundle_idstringNoThe app's bundle identifier (used as the APNs topic).
environmentstringNosandbox or production. Defaults to sandbox.

Response — 200 OK

{
"id": "cred-1",
"channel_id": "6f1d2a34-9c1b-4e8a-b0d2-1a2b3c4d5e6f",
"type": "apns",
"created_at": "2026-07-27T12:01:00Z",
"updated_at": "2026-07-27T12:01:00Z"
}

POST /api/v1/channels/:id/credentials/fcm

Uploads a Firebase service-account key for an android channel. The request is multipart/form-data.

Form fields

FieldTypeRequiredDescription
key_filefileYesThe Firebase service-account JSON key file.

Response — 200 OK

The credential confirmation object (same shape as APNs, with "type": "fcm").

POST /api/v1/channels/:id/credentials/vapid

Generates a VAPID key pair server-side for a web_push channel. No request body is required. The response includes the generated public key so you can register it with the browser's push manager; the private key stays encrypted server-side and is never exposed.

Response — 200 OK

{
"id": "cred-2",
"channel_id": "9a8b7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
"type": "vapid",
"vapid_public_key": "BODl3v8Yx...",
"created_at": "2026-07-27T12:01:00Z",
"updated_at": "2026-07-27T12:01:00Z"
}

POST /api/v1/channels/:id/credentials/sms

Beta

SMS is in Beta. SMS channels are provisioned by the Hober team during the Beta; contact support to enable the channel type on your workspace.

Uploads SMS provider credentials for an sms channel. JSON body.

Request Body

{
"api_key": "...",
"api_secret": "...",
"sender_id": "..."
}
FieldTypeRequiredDescription
api_keystringYesProvider API key.
api_secretstringYesProvider API secret.
sender_idstringYesRegistered sender ID or phone number.

Response — 200 OK

The credential confirmation object with "type": "sms".

POST /api/v1/channels/:id/credentials/whatsapp

Beta

WhatsApp is in Beta. WhatsApp channels are provisioned by the Hober team during the Beta; contact support to enable the channel type on your workspace.

Uploads WhatsApp Business (Meta Cloud API) credentials for a whatsapp channel. JSON body.

Request Body

{
"access_token": "...",
"phone_number_id": "...",
"waba_id": "...",
"app_secret": "...",
"webhook_verify_token": "..."
}
FieldTypeRequiredDescription
access_tokenstringYesMeta system-user access token.
phone_number_idstringYesThe WhatsApp Business phone number ID.
waba_idstringYesThe WhatsApp Business Account ID.
app_secretstringNoMeta app secret — required only to receive inbound webhooks (opt-outs, template status callbacks).
webhook_verify_tokenstringNoVerify token for the Meta webhook subscription.

Response — 200 OK

The credential confirmation object with "type": "whatsapp".


WhatsApp message templates

Beta

Part of the WhatsApp Beta — see above.

WhatsApp marketing messages must use a Meta-approved template. These endpoints manage the template lifecycle: draft locally, submit to Meta for review, then poll the approval status.

The template object

FieldTypeDescription
idstringTemplate UUID.
channel_idstringThe owning whatsapp channel.
namestringTemplate name.
languagestringTemplate language code.
categorystringMeta template category.
bodystringTemplate body text.
statusstringLocal approval state of the template.
provider_template_idstringMeta's template ID, present after submission.
status_reasonstringMeta's rejection reason, when present.
created_atstringCreation timestamp.
updated_atstringLast-update timestamp.

POST /api/v1/channels/:id/whatsapp-templates

Creates a template draft.

Request Body

{
"name": "order_shipped",
"language": "en_US",
"category": "MARKETING",
"body": "Your order is on the way!"
}
FieldTypeRequiredDescription
namestringYesTemplate name.
bodystringYesTemplate body text.
languagestringNoLanguage code.
categorystringNoMeta template category.

Returns 201 with the template object.

GET /api/v1/channels/:id/whatsapp-templates

Lists the channel's templates.

Response — 200 OK

{ "items": [ { "id": "...", "name": "order_shipped", "status": "..." } ] }

POST /api/v1/channels/:id/whatsapp-templates/:templateId/submit

Submits the draft to Meta for review. Returns 200 with the updated template object, including the provider_template_id assigned by Meta.

POST /api/v1/channels/:id/whatsapp-templates/:templateId/refresh

Pulls the current approval status from Meta and applies it. Returns 200 with the updated template object — check status and, on rejection, status_reason.