Sub-accounts
For agencies running one Ready account per customer. Each sub-account has its own numbers and registration, and pays for its own texts with its own card and balance unless you create it with billing: "agency". Call these with an rsms_ key from your own account, and act inside a sub-account with X-Sub-Account-Id. Set a sub-account’s prices with partner fees. The API can’t remove a sub-account: in the app, open it under Sub-accounts and choose Remove sub-account. That deletes its contacts, conversations and call logs, so export them first with GET /contacts/export and GET /sms/export, sending X-Sub-Account-Id.
#Set up a sub-account
POST /v1/sub-accountscreates the sub-account.- Register its brand with Register, sending
X-Sub-Account-Id. POST /v1/team-membersgives a person a login.- Optional, approved partners only: set their prices with Partner fees.
To list your sub-accounts with sends, replies, spend and registration, call GET /v1/partner/clients. It works for every agency, with or without the Partner program; the name is historical.
The API has no call to remove a sub-account. To remove one, open Sub-accounts in the dashboard and choose Remove sub-account. You pick what happens to its numbers first.
#The Sub-account object
idinteger- The sub-account’s id, the same number as its Ready ID in the app. Send it as
X-Sub-Account-Id. emailstring- The sub-account owner’s email.
first_name, last_namestring- The owner’s name. Not in the create response.
company_namestring- The sub-account’s business name.
statusstring- The sub-account’s status, for example
active. Not in the create response. account_kindstringclientfor a sub-account with an owner,workspacefor one you run yourself with no owner email. A sub-account you pay for (billing: "agency", Me in the app’s Add sub-account dialog) is either one: see Sub-accounts.billingstring- Who pays. Possible values:
client,agency. created_atstring- When the sub-account was made, ISO 8601. Not in the create response.
shares_owner_capacityboolean or null- Whether the sub-account texts under your registration while it has none of its own.
nullfor a sub-account that pays for itself: it never texts under yours. Not in the create response. shared_daily_limitinteger or null- How many texts a day, on all carriers, it may send under your registration.
nullmeans no limit of its own. Not in the create response. client_ratenull- Only in the create response, and always
null: a new sub-account starts at Ready’s price, with no markup. invite_linkstring- Only in the create response. The sub-account’s sign-in link, to send yourself when
send_inviteisfalse.
Legacy fields (2)
kindstring- The older name for
account_kind, same value. It still works. Not in the create response. markup_usd_per_segmentnumber or null- The sub-account’s legacy per-segment markup, in dollars, or
nullwhen it has none. It can only be removed (Older paths). Not in the create response.
#Create a sub-account
Creates a sub-account with its own login, card, numbers and registration. Needs the Manage team permission (invite_team).
Parameters
emailstringRequired unless billing is agency- The sub-account owner’s email. Leave it out only with
billing: "agency", which makes a sub-account you run yourself; that create answers 201 withid,company_name,ownerless: true,account_kindandinvite_email_sent, withoutinvite_linkorclient_rate(Sub-accounts). first_name, last_namestringcompany_namestringcompany_nameis required whenemailis left out.send_invitebooleanDefaulttrue- Emails the sub-account an invite to set up their login and card. Send
falseto skip the email and send theminvite_linkyourself. billingstringDefaultclientclient: the sub-account adds their own card and pays their own bill.agency: your card pays for the sub-account’s registration, numbers and messages, at your prices. The API has no call to change it later.
Returns a Sub-account object in data.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_request | Missing email unless billing is agency, or missing company_name when email is left out. |
| 400 | unknown_field | A field it doesn’t accept. |
| 403 | agency_only | Your account is another agency’s sub-account. Use your main account’s key. |
| 409 | client_already_yours | Already your sub-account. Find its id with List sub-accounts. |
| 409 | email_has_account | That email already has its own account. Contact support to link it. |
| 409 | email_reserved | Email can’t be used (403 for a staff address). |
#List sub-accounts
The sub-accounts you manage, and your own business accounts, newest first. Pages with a cursor. Needs the Manage team permission (invite_team).
Parameters
limitinteger · queryDefault50Max200- Page size.
before_idinteger · query- The
next_before_idfrom the previous page.
Returns a list of Sub-account objects in data.
Returns
has_morebooleantruewhen another page follows. Keep paging while it’strue.next_before_idinteger | null- Pass as
before_id.
#Get a sub-account
One sub-account, as the list returns it, including your own business accounts (account_kind workspace). Needs the Manage team permission (invite_team).
Parameters
idinteger · pathRequired- The sub-account id.
Returns a Sub-account object in data.
Errors
| HTTP | Code | When |
|---|---|---|
| 404 | sub_account_not_found | Not a sub-account you manage. |
#Set capacity sharing
These two settings choose whether a sub-account texts under your registration, and how many texts a day it may send there. We count 4 in 10 of its daily limit against your T-Mobile daily cap, since about 1 in 3 US phones is on T-Mobile. Once its own registration is approved, it texts under that one instead and the limit no longer applies. Needs the Manage team permission (invite_team).
Parameters
idinteger · pathRequired- The sub-account id.
Send at least one of the two. Returns the updated Sub-account object in data.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_request | Neither field was sent, or a value is the wrong type or out of range. |
| 403 | organization_only | The key’s user has Organization only access, so it can’t change a sub-account. |
| 404 | sub_account_not_found | Not a sub-account you manage. |
| 409 | not_a_sharing_sub_account | The sub-account pays for itself, so it never texts under your registration. |
#Give a sub-account a setup
Installs a snapshot into a sub-account: its templates, drip campaigns, automations, campaigns, lists, custom fields and contact pipelines, matched by name so nothing is added twice. Automations arrive off, and drip campaigns and campaigns arrive as drafts. Make a snapshot with Create a snapshot, and find its key with List your snapshots. Needs the Campaigns permission (manage_campaigns). In the app, a sub-account’s page has a Snapshot card that installs one.
Parameters
X-Sub-Account-Idinteger · header- The sub-account to install it into. Leave it out to install into your own account.
keystringRequired- The snapshot’s share key.
Returns
Counts of what was added, such as automations_created, templates_created, drips_created, campaigns_created, pipelines_created and stages_added. Running it again adds nothing. items lists each thing added with its kind (a drip campaign is sequence), and refused lists the kinds our content checks turned away (campaign, template, drip). Moving a phone number between accounts is Move a number to a sub-account.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_request | key is missing. |
| 400 | OWN_SNAPSHOT | You made this snapshot, so its setup is already in your account. |
| 403 | permission_denied | Key lacks manage_campaigns. |
| 404 | SNAPSHOT_NOT_FOUND | No snapshot has that key. Check it with List your snapshots. |
| 500 | SNAPSHOT_DAMAGED | The snapshot can’t be read. Make a new snapshot and use its key. |
| 500 | IMPORT_PARTIAL | Some items were added and data.failed lists the kinds that were not. Send the same request again: nothing is added twice. |
| 500 / 503 | IMPORT_RETRY | Nothing was installed. Send it again in a minute. |
#List your snapshots
The snapshots your account made, newest first, with the share key Give a sub-account a setup takes. Needs the Campaigns permission (manage_campaigns).
Returns
data[]object[]key(the share key),label,url(the share link),apply_count(how many times it was installed),created_atandcounts(automations,templates,drips,campaigns,pipelines).
Errors
| HTTP | Code | When |
|---|---|---|
| 403 | permission_denied | The key’s user can’t manage campaigns. |
| 500 | request_failed | The list couldn’t be read. Retry. |
#Create a snapshot
Packs the items you pick into a new snapshot and gives back its share key. It reads only your own items and changes nothing in the account. Sending it again makes a second snapshot with a new key. Needs the Campaigns permission (manage_campaigns).
Parameters
labelstringDefaultMy setup- A name for it, up to 80 characters.
accountinteger- Take the items from this sub-account instead of your own account. The snapshot is still yours.
automations, templates, drips, campaignsinteger[]- The ids of the items to include. Pick at least one item in all.
pipelinesstring[]- The contact pipelines to include, by id.
Returns data.key, data.label, data.url and data.counts.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_request, unknown_field | A field of the wrong type, or one it doesn’t accept. |
| 400 | request_failed | Nothing picked, or none of the picked items are on the account. |
| 403 | request_failed | account isn’t one of your accounts. |
| 403 | permission_denied | The key’s user can’t manage campaigns. |
| 500 | request_failed | No snapshot was made. Retry. |
#Move a number to a sub-account
Gives a number your account holds to one of your own sub-accounts. It can text from it right away, and you keep paying for it. Call forwarding on the number is turned off, and its caller ID name is removed; the sub-account can set its own. To take it back, call Unassign a number (POST /v1/numbers/:id/unassign). If the sub-account has its own approved registration with room, the number moves onto it.
404.Path parameters
idintegerRequired- The number id.
Body parameters
sub_account_idintegerRequired- The sub-account to give it to.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_field | sub_account_id is missing. |
| 400 | SUB_ACCOUNT_REQUIRED | sub_account_id is not an id. |
| 403 | permission_denied | Key lacks manage_phones. |
| 404 | NUMBER_NOT_FOUND | The number isn’t yours. A second call on a number already moved answers 404. |
| 404 | sub_account_not_found | The sub-account isn’t one of yours, or it pays for itself and buys its own numbers. |
| 409 | NUMBER_ASSIGN_BLOCKED | This number can’t be moved; reason says why. |
| 500 | ASSIGN_NOT_APPLIED | Nothing moved. Check GET /v1/numbers/:id and send it again. |
| 500 | MOVE_UNCONFIRMED | Check GET /v1/numbers/:id before trying again. |
Older paths
PUT /v1/sub-accounts/:id/rate: only clears a sub-account’s legacy markup. Send {"markup": 0}, or {"use_default": true} when your default markup is 0. Needs the Manage team permission (invite_team). A sub-account that already pays a markup keeps paying it until you remove it, and you can’t add it back: use partner fees instead. Returns data.markup, data.is_custom, data.base_rate (your rate) and data.client_rate (null means Ready’s standard price).
400 markup_retired: a markup above 0, oruse_defaultwith a default above 0.400 invalid_request: a negative markup, or nothing to change.400 unknown_field: a field it doesn’t accept.403 forbidden: not your main account.404 sub_account_not_found: not a sub-account you manage.409 rate_locked: contact support.dialer_markupanduse_default_dialer(a call markup) are saved. A sub-account you bill pays this markup on each billed call minute. Above 0 they can be refused withterms_required,reseller_not_approved,forbidden, orinvalid_markupabove $0.06.
See also: the guide to doing this in the app.