SMS API for small business
From 1¢/message · approved in hours · no 10DLC forms
pnpm add @textycally/sdk import { TextycallyClient } from '@textycally/sdk';
const client = new TextycallyClient({ apiKey: process.env.TEXTYCALLY_API_KEY! });
await client.messages.send({
idempotencyKey: 'order-42-ready',
recipients: [{ address: { channel: 'sms', phone: '+14155552671' } }],
payloads: { sms: { channel: 'sms', body: 'Your order is ready!' } },
}); uv pip install textycally import os
import textycally
from textycally.models import ( NotificationRequest, NotificationRecipient, RecipientAddress, SmsAddress, ChannelPayloadMap, SmsPayload )
config = textycally.Configuration(access_token=os.environ["TEXTYCALLY_API_KEY"])
with textycally.ApiClient(config) as client:
api = textycally.NotificationsApi(client)
api.notifications_create(NotificationRequest(
idempotency_key="order-42-ready",
recipients=[NotificationRecipient(address=RecipientAddress(SmsAddress(channel="sms", phone="+14155552671")))],
payloads=ChannelPayloadMap(sms=SmsPayload(channel="sms", body="Your order is ready!")),
)) go get forge.blackleafdigital.com/BlackLeafDigital/TextyCally/sdks/go package main
import (
"context"
"os"
textycally "forge.blackleafdigital.com/BlackLeafDigital/TextyCally/sdks/go"
)
func main() {
client := textycally.NewAPIClient(textycally.NewConfiguration())
ctx := context.WithValue(context.Background(), textycally.ContextAccessToken, os.Getenv("TEXTYCALLY_API_KEY"))
req := textycally.NotificationRequest{
IdempotencyKey: "order-42-ready",
Recipients: []textycally.NotificationRecipient{{
Address: textycally.SmsAddressAsRecipientAddress(textycally.NewSmsAddress("sms", "+14155552671")),
}},
Payloads: textycally.ChannelPayloadMap{Sms: textycally.NewSmsPayload("sms")},
}
req.Payloads.Sms.SetBody("Your order is ready!")
client.NotificationsAPI.NotificationsCreate(ctx).NotificationRequest(req).Execute()
} composer require textycally/sdk <?php
use Textycally\Sdk\Configuration;
use Textycally\Sdk\Api\NotificationsApi;
use Textycally\Sdk\Model\{NotificationRequest, NotificationRecipient, RecipientAddress, SmsAddress, ChannelPayloadMap, SmsPayload};
$config = Configuration::getDefaultConfiguration()->setAccessToken(getenv('TEXTYCALLY_API_KEY'));
$api = new NotificationsApi(new GuzzleHttp\Client(), $config);
$api->notificationsCreate(new NotificationRequest([
'idempotencyKey' => 'order-42-ready',
'recipients' => [new NotificationRecipient(['address' => new RecipientAddress(['channel' => 'sms', 'phone' => '+14155552671'])])],
'payloads' => new ChannelPayloadMap(['sms' => new SmsPayload(['channel' => 'sms', 'body' => 'Your order is ready!'])]),
])); <!-- pom.xml -->
<dependency>
<groupId>com.textycally</groupId>
<artifactId>textycally-sdk</artifactId>
<version>0.1.0</version>
</dependency> import com.textycally.sdk.*;
import com.textycally.sdk.api.NotificationsApi;
import com.textycally.sdk.model.*;
ApiClient client = Configuration.getDefaultApiClient();
client.setBearerToken(System.getenv("TEXTYCALLY_API_KEY"));
new NotificationsApi(client).notificationsCreate(new NotificationRequest()
.idempotencyKey("order-42-ready")
.recipients(List.of(new NotificationRecipient().address(new RecipientAddress(new SmsAddress().channel(SmsAddress.ChannelEnum.SMS).phone("+14155552671"))))
.payloads(new ChannelPayloadMap().sms(new SmsPayload().channel(SmsPayload.ChannelEnum.SMS).body("Your order is ready!")))); cargo add textycally-sdk use textycally_sdk::{apis::{configuration::Configuration, notifications_api::notifications_create}, models};
let config = Configuration {
bearer_access_token: Some(std::env::var("TEXTYCALLY_API_KEY").unwrap()),
..Default::default()
};
let req = models::NotificationRequest {
idempotency_key: "order-42-ready".into(),
recipients: vec![models::NotificationRecipient::new(models::RecipientAddress::SmsAddress(Box::new(models::SmsAddress::new(Default::default(), "+14155552671".into())))))],
payloads: Box::new(models::ChannelPayloadMap {
sms: Some(Box::new(models::SmsPayload { body: Some("Your order is ready!".into()), ..Default::default() })),
..Default::default()
}),
..Default::default()
};
notifications_create(&config, req).await?; # no install — any HTTP client works curl -X POST https://relay.blackleafdigital.com/v1/notifications \
-H "Authorization: Bearer $TEXTYCALLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"idempotencyKey": "order-42-ready",
"recipients": [{ "address": { "channel": "sms", "phone": "+14155552671" } }],
"payloads": { "sms": { "channel": "sms", "body": "Your order is ready!" } }
}' // inbound replies + delivery updates over SSE
// (client.events.connect gives you the same over WS)
const conn = client.events.stream({
onEvent: (e) => {
if (e.type === 'message.received')
reply(e.data.from, e.data.text);
},
}); <!-- hosted opt-in form, TCPA-logged for you -->
<iframe
src="https://relay.blackleafdigital.com
/v1/embed/YOUR_PK/consent/widget"
width="100%" height="420">
</iframe> | Textycally Texting for humans | Twilio A2P 10DLC route | |
|---|---|---|
| Time to first message | Hours A human approves your account, usually same day | Days to weeks 10DLC brand + campaign vetting before traffic flows |
| 10DLC campaign registration forms | Not part of our product | Brand + campaign registration required for local numbers |
| Pricing model | Flat per message From 1¢ — the price on the page is the price you pay | Base rate + fees Per-segment rate plus carrier and campaign fees |
| Onboarding | A person reads your form And emails you back | Automated vetting pipeline Rejections arrive without a human to ask |
| Two-way inbox included | Conversations, transcripts, live streaming | Build your own on top of webhooks |
| Contracts & minimums | Prepaid credits, stop whenever | Pay-as-you-go, but committed-use discounts gated |
How fast can I actually send my first message?
Sign up, fill in the business review form (it is one page), and a human approves it — usually within hours. Your API key works the moment you are approved, and your first number is one click in the dashboard.
Do I need to register a 10DLC brand and campaign?
No. 10DLC campaign registration is not part of our product — we route business texting over our own managed relay fleet, and our human review replaces the campaign-form gauntlet.
What does a message cost?
Flat per-message pricing from 1¢, paid from a prepaid credit balance (1 credit = 1¢). No carrier surcharges, no campaign fees, no monthly platform fee on pay-as-you-go.
Can my customers text me back?
Yes — every dedicated number is two-way. Replies arrive in the dashboard inbox with full transcripts and live streaming, and you can consume them programmatically via webhooks.
Is there a contract or a monthly minimum?
No contract, no minimum. Buy credits when you need them; they do not expire. Monthly plans exist only to lower your per-message rate.
What happens if you are at capacity?
Sending capacity comes from our relay fleet. When it is fully subscribed, new signups join a waitlist and we email you the moment a slot opens — existing customers are never throttled to make room.