# Send Campaigns

## Create a Campaign in Flow Builder

{% hint style="info" %}
Reach out to your Account Manager for details on how to set up a campaign/flow.&#x20;
{% endhint %}

The Connectly Message Service API allows you to send a sequence of messages (bot/flow) from one API call by adding the `campaignName` parameter.

Your account manager can help you with the flow and share the campaign name that you invoke in the API request.

Here are the steps on how to find the `campaignName` parameter on your own.

### Create your campaign in the inbox

1. Go to the inbox [https://inbox.connectly.ai](https://inbox.connectly.ai/home)
2. Click on Create new Campaign\
   ![](https://1088238995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTPnSja6RkBiRLGAbuXVJ%2Fuploads%2FAslEKWCjew1SK3gDrbyT%2FScreenshot%202025-05-06%20at%2017.31.45.png?alt=media\&token=b2843b02-cc7c-4f71-889a-b29c74288e86)
3. Create New Campaign\
   ![](https://1088238995-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTPnSja6RkBiRLGAbuXVJ%2Fuploads%2Fe6Zr4YPNhMa2RYzPWJzP%2FCleanShot%202023-06-21%20at%2019.41.52%402x.png?alt=media\&token=475d8a17-30a1-468f-a81b-dff4ce6f0802)
4. Go through all the steps and send campaign to yourself (WhatsApp phone number)
5. Verify that the campaign was sent succesfully
6. Go back to Flow Builder
7. Select Resend or Edit a Campaign
8. Find your campaign and copy the name of it
9. Use it in the `campaignName in` [#initiate-campaign-sendout](#initiate-campaign-sendout "mention")

```json
{
     "sender": "+14151111234",
     "number": "+1(604) 585 2331",
     "templateName": "tempalte", 
     "language": "en",
     "parameters": [],
     "campaignName": "template123" 
}
```

## Initiate Campaign Sendout

You can use this endpoint to initiate a sendout of one or more campaigns.

Each entry in the body contains information about the campaign and its recipient.

## POST /v1/businesses/{businessId}/send/campaigns

> API to send campaigns to multiple recipients.

```json
{"openapi":"3.1.1","info":{"title":"Campaign API","version":"1.0"},"tags":[{"name":"CampaignService","description":"API for sending campaigns"}],"security":[{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","description":"API key for authorization","name":"X-API-Key","in":"header"}},"schemas":{"v1SendCampaignsResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","$ref":"#/components/schemas/dtoSendCampaignsSubmissionStatus"},"description":"List of reports for the executed sendouts.","title":"Data"}}},"dtoSendCampaignsSubmissionStatus":{"type":"object","properties":{"campaignId":{"type":"string","description":"The id of the campaign","title":"Campaign Id"},"campaignName":{"type":"string","description":"The identifier of the campaign.","title":"Campaign Name"},"campaignVersion":{"type":"string","description":"The identifier of the campaign version.","title":"Campaign Version"},"sendoutId":{"type":"string","description":"The id of the sendout.","title":"Sendout Id"},"status":{"$ref":"#/components/schemas/campaignCampaignSubmissionStatus","description":"The status of the campaign submission.","title":"Status"},"acceptedCount":{"type":"integer","format":"int64","description":"The number of entries for this campaign that were accepted.","title":"Accepted Count"},"rejectedCount":{"type":"integer","format":"int64","description":"The number of entries for this campaign that were rejected.","title":"Rejected Count"},"error":{"$ref":"#/components/schemas/errorPartialError","description":"The error indicating what went wrong with the submission. (status == 'error')","title":"Error"}}},"campaignCampaignSubmissionStatus":{"type":"string","enum":["unspecified","error","created","updated"],"default":"unspecified","title":"buf:lint:ignore ENUM_VALUE_UPPER_SNAKE_CASE\nbuf:lint:ignore ENUM_VALUE_PREFIX\nbuf:lint:ignore ENUM_ZERO_VALUE_SUFFIX"},"errorPartialError":{"type":"object","properties":{"message":{"type":"string","description":"A human-readable description of the error.","title":"Message"},"type":{"$ref":"#/components/schemas/errorErrorType","description":"The type of the error indicating a broad category.","title":"Type"},"code":{"$ref":"#/components/schemas/errorErrorCode","description":"The specific error code indicating the exact error.","title":"Code"},"userTitle":{"type":"string","description":"A more user friendly title describing the error.","title":"User title"},"userMessage":{"type":"string","description":"A more user friendly message describing the error including fix suggestions.","title":"User message"}},"description":"The `PartialError` type defines information about an error that occurred in invoking a multi-purpose api."},"errorErrorType":{"type":"string","enum":["ERROR_TYPE_UNSPECIFIED","ERROR_TYPE_CANCELLED","ERROR_TYPE_UNKNOWN","ERROR_TYPE_INVALID_ARGUMENT","ERROR_TYPE_DEADLINE_EXCEEDED","ERROR_TYPE_NOT_FOUND","ERROR_TYPE_ALREADY_EXISTS","ERROR_TYPE_PERMISSION_DENIED","ERROR_TYPE_RESOURCE_EXHAUSTED","ERROR_TYPE_FAILED_PRECONDITION","ERROR_TYPE_ABORTED","ERROR_TYPE_OUT_OF_RANGE","ERROR_TYPE_UNIMPLEMENTED","ERROR_TYPE_INTERNAL","ERROR_TYPE_UNAVAILABLE","ERROR_TYPE_DATA_LOSS","ERROR_TYPE_UNAUTHENTICATED","ERROR_TYPE_REQUEST_ENTITY_TOO_LARGE","ERROR_TYPE_AUTHENTICATION","ERROR_TYPE_AUTHORIZATION","ERROR_TYPE_RATE_LIMIT","ERROR_TYPE_INVALID_REQUEST","ERROR_TYPE_CONFLICT","ERROR_TYPE_CONTEXT_CANCLED","ERROR_TYPE_BUSINESS_LIMIT","ERROR_TYPE_WEBHOOK_DELIVERY_FAILED","ERROR_TYPE_FAILED_TO_PERSIST"],"default":"ERROR_TYPE_UNSPECIFIED","title":"- ERROR_TYPE_CANCELLED: The operation was cancelled, typically by the caller.\n - ERROR_TYPE_UNKNOWN: Unknown error. For example, this error may be returned when a Status value received from another address space belongs to an error space that is not known in this address space. Also errors raised by APIs that do not return enough error information may be converted to this error.\n - ERROR_TYPE_INVALID_ARGUMENT: The client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the system (e.g., a malformed file name).\nNOTE: this is generated by user-code only.\n - ERROR_TYPE_DEADLINE_EXCEEDED: The deadline expired before the operation could complete. For operations that change the state of the system, this error may be returned even if the operation has completed successfully. For example, a successful response from a server could have been delayed long enough for the deadline to expire.\n - ERROR_TYPE_NOT_FOUND: Some requested entity (e.g., file or directory) was not found. Note to server developers: if a request is denied for an entire class of users, such as gradual feature rollout or undocumented allowlist, NOT_FOUND may be used. If a request is denied for some users within a class of users, such as user-based access control, PERMISSION_DENIED must be used.\nNOTE: this is generated by user-code only.\n - ERROR_TYPE_ALREADY_EXISTS: The entity that a client attempted to create (e.g., file or directory) already exists.\nNOTE: this is generated by user-code only.\n - ERROR_TYPE_PERMISSION_DENIED: The caller does not have permission to execute the specified operation. PERMISSION_DENIED must not be used for rejections caused by exhausting some resource (use RESOURCE_EXHAUSTED instead for those errors). PERMISSION_DENIED must not be used if the caller can not be identified (use UNAUTHENTICATED instead for those errors). This error code does not imply the request is valid or the requested entity exists or satisfies other pre-conditions.\n - ERROR_TYPE_RESOURCE_EXHAUSTED: Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system is out of space.\n - ERROR_TYPE_FAILED_PRECONDITION: The operation was rejected because the system is not in a state required for the operation’s execution. For example, the directory to be deleted is non-empty, an rmdir operation is applied to a non-directory, etc. Service implementors can use the following guidelines to decide between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: (a) Use UNAVAILABLE if the client can retry just the failing call. (b) Use ABORTED if the client should retry at a higher level (e.g., when a client-specified test-and-set fails, indicating the client should restart a read-modify-write sequence). (c) Use FAILED_PRECONDITION if the client should not retry until the system state has been explicitly fixed. E.g., if an “rmdir” fails because the directory is non-empty, FAILED_PRECONDITION should be returned since the client should not retry unless the files are deleted from the directory.\n - ERROR_TYPE_ABORTED: The operation was aborted, typically due to a concurrency issue such as a sequencer check failure or transaction abort. See the guidelines above for deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE.\n - ERROR_TYPE_OUT_OF_RANGE: The operation was attempted past the valid range. E.g., seeking or reading past end-of-file. Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system state changes. For example, a 32-bit file system will generate INVALID_ARGUMENT if asked to read at an offset that is not in the range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from an offset past the current file size. There is a fair bit of overlap between FAILED_PRECONDITION and OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error) when it applies so that callers who are iterating through a space can easily look for an OUT_OF_RANGE error to detect when they are done.\n - ERROR_TYPE_UNIMPLEMENTED: The operation is not implemented or is not supported/enabled in this service.\n - ERROR_TYPE_INTERNAL: Internal errors. This means that some invariants expected by the underlying system have been broken. This error code is reserved for serious errors.\n - ERROR_TYPE_UNAVAILABLE: The service is currently unavailable. This is most likely a transient condition, which can be corrected by retrying with a backoff. Note that it is not always safe to retry non-idempotent operations.\n - ERROR_TYPE_DATA_LOSS: Unrecoverable data loss or corruption.\n - ERROR_TYPE_UNAUTHENTICATED: The request does not have valid authentication credentials for the operation.\n - ERROR_TYPE_AUTHENTICATION: DEPRECATED: use UNAUTHENTICATED\n - ERROR_TYPE_AUTHORIZATION: DEPRECATED: use PERMISSION_DENIED\n - ERROR_TYPE_RATE_LIMIT: DEPRECATED: this should be a sub-code of RESOURCE_EXHAUSTED\n - ERROR_TYPE_INVALID_REQUEST: DEPRECATED: use INVALID_ARGUMENT\n - ERROR_TYPE_CONFLICT: DEPRECATED: use ALREADY_EXISTS or FAILED_PRECONDITION\n - ERROR_TYPE_CONTEXT_CANCLED: DEPRECATED: use CANCELLED, ABORTED, or DEADLINE_EXCEEDED\n - ERROR_TYPE_BUSINESS_LIMIT: DEPRECATED: this should be a sub-code of RESOURCE_EXHAUSTED\n - ERROR_TYPE_WEBHOOK_DELIVERY_FAILED: DEPRECATED: currently no use\n - ERROR_TYPE_FAILED_TO_PERSIST: DEPRECATED: currently no use"},"errorErrorCode":{"type":"string","enum":["ERROR_CODE_UNSPECIFIED","ERROR_CODE_BAD_REQUEST","ERROR_CODE_NOT_FOUND","ERROR_CODE_UNAUTHENTICATED","ERROR_CODE_PERMISSION_DENIED","ERROR_CODE_CONFLICT","ERROR_CODE_CONTEXT_CANCELED","ERROR_CODE_DEADLINE_EXCEEDED","ERROR_CODE_THROTTLED","ERROR_CODE_DEPRECATED","ERROR_CODE_UNCONFIRMED_USER","ERROR_CODE_NONCOMPLIANT_PASSWORD","ERROR_CODE_CREATE_USER_CONFLICT","ERROR_CODE_CREATE_BUSINESS_CONFLICT","ERROR_CODE_ASSOCIATE_SMS_CONFLICT","ERROR_CODE_ASSOCIATE_EMAIL_CONFLICT","ERROR_CODE_BUSINESS_NOT_FOUND","ERROR_CODE_CUSTOMER_NOT_FOUND","ERROR_CODE_INVALID_BUSINESS_CHANNEL","ERROR_CODE_INVALID_CUSTOMER_CHANNEL","ERROR_CODE_EVENT_ALREADY_MARKED_MAPPED","ERROR_CODE_EVENT_ALREADY_MARKED_SENT","ERROR_CODE_MESSAGE_TOO_LONG","ERROR_CODE_APPROVED_WABA_TEMPLATE_NOT_FOUND","ERROR_CODE_WABA_TEMPLATED_MESSAGE_INPUT_INVALID","ERROR_CODE_MISSING_BUSINESS_CHANNEL","ERROR_CODE_PLATFORM_INVOCATION_ERROR","ERROR_CODE_BAD_FACEBOOK_VERIFICATION_REQUEST","ERROR_CODE_PLATFORM_EXTERNAL_WEBHOOK_DELIVERY_TIMEOUT","ERROR_CODE_CAMPAIGN_CONFIG_NAME_CONFLICT","ERROR_CODE_INVALID_CAMPAIGN_CONFIG_NAME","ERROR_CODE_ANOTHER_SENDOUT_RUNNING","ERROR_CODE_CAMPAIGN_NO_LONGER_EDITABLE","ERROR_CODE_CAMPAIGN_NOT_FOUND","ERROR_CODE_CAMPAIGN_NOT_FINAL","ERROR_CODE_CAMPAIGN_UNSUPPORTED","ERROR_CODE_CAMPAIGN_ENTRY_INVALID","ERROR_CODE_CAMPAIGN_VERSION_NOT_FOUND","ERROR_CODE_CAMPAIGN_VERSION_NOT_FINAL","ERROR_CODE_CAMPAIGN_VERSION_FINAL","ERROR_CODE_CAMPAIGN_VERSION_UNSUPPORTED","ERROR_CODE_CAMPAIGN_ENTRY_CLIENT_INVALID","ERROR_CODE_CAMPAIGN_TOO_MANY_ENTRIES","ERROR_CODE_CAMPAIGN_LARGE_REQUEST","ERROR_CODE_ASSET_FETCHING_ERROR","ERROR_CODE_ASSET_STAGING_ERROR","ERROR_CODE_ASSET_EXCEEDS_SIZE_LIMIT","ERROR_CODE_INVALID_SENDER_ID","ERROR_CODE_FAILED_TO_DELIVER_WEBHOOK_EVENT","ERROR_CODE_PHONE_NUMBER_BAD_FORMAT","ERROR_CODE_MESSAGE_ATTACHMENTS_NUMBER_INVALID","ERROR_CODE_MESSAGE_TEXT_EMPTY","ERROR_CODE_MESSAGE_TEMPLATE_NOT_FOUND","ERROR_CODE_MESSAGE_TEMPLATE_INPUT_INVALID","ERROR_CODE_MESSAGE_ATTACHMENT_EMPTY","ERROR_CODE_MESSAGE_ATTACHMENT_INVALID","ERROR_CODE_BUSINESS_MISSES_MATCHING_CHANNEL","ERROR_CODE_MESSAGE_OUTSIDE_OF_ELIGIBILITY_WINDOW","ERROR_CODE_BUSINESS_REACHED_LIMITS","ERROR_CODE_MESSAGE_SELF_INVALID","ERROR_CODE_MESSAGE_PHONE_NUMBER_INVALID","ERROR_CODE_MESSAGE_CUSTOMER_OPTED_OUT","ERROR_CODE_MESSAGE_CUSTOMER_NO_CONVERSATION_INITIATION","ERROR_CODE_BUSINESS_KEY_SECRET_ABSENT","ERROR_CODE_MESSAGE_TEMPLATE_DELETED","ERROR_CODE_MESSAGE_PHONE_NUMBER_NOT_ON_WHATSAPP","ERROR_CODE_MESSAGE_UNDELIVERABLE","ERROR_CODE_META_CHOSE_NOT_TO_DELIVER","ERROR_CODE_MESSAGE_TEMPLATE_DUPLICATED_LANGUAGE","ERROR_CODE_MESSAGE_TEMPLATE_INVALID_NAME","ERROR_CODE_MESSAGE_TEMPLATE_INVALID_LANGUAGE","ERROR_CODE_MESSAGE_TEMPLATE_DELETE_NOT_FOUND","ERROR_CODE_MESSAGE_TEMPLATE_INVALID_PARAM","ERROR_CODE_MESSAGE_TEMPLATE_CATEGORY_NOT_MATCH","ERROR_CODE_BUSINESS_RATE_LIMIT_REACHED","ERROR_CODE_MESSAGE_WABA_TEMPLATE_INVALID_BUTTON_PARAM","ERROR_CODE_MESSAGE_WABA_TEMPLATE_INVALID_HEADER_PARAM","ERROR_CODE_MESSAGE_WABA_TEMPLATES_LIMIT_REACHED","ERROR_CODE_MESSAGE_TEMPLATE_DUPLICATED_CONTENT","ERROR_CODE_MESSAGE_TEMPLATE_VARIABLE_LENGTH_EXCEEDS","ERROR_CODE_MISSING_PERMISSIONS","ERROR_CODE_MESSAGE_TEMPLATE_FAILED_TO_PERSIST","ERROR_CODE_MESSAGE_WABA_TEMPLATE_STATUS_IS_NOT_EDITABLE","ERROR_CODE_MESSAGE_WABA_TEMPLATE_EDIT_REJECTED","ERROR_CODE_MESSAGE_WABA_TEMPLATE_CAN_ONLY_EDIT_ONCE_IN_24_HOURS","ERROR_CODE_WA_API_SERVICE_TEMPORARILY_UNAVAILABLE","ERROR_CODE_MESSAGE_WABA_TEMPLATE_IS_PAUSED","ERROR_CODE_MESSAGE_WABA_TEMPLATE_IS_DISABLED","ERROR_CODE_WA_PHONE_NUMBER_IN_EXPERIMENT","ERROR_CODE_WA_SERVER_TEMPORARILY_UNAVAILABLE","ERROR_CODE_WA_PHONE_NUMBER_NOT_REGISTERED","ERROR_CODE_WA_ACCOUNT_LOCKED","ERROR_CODE_WA_SOMETHING_WENT_WRONG","ERROR_CODE_WA_REQUIRED_PARAMETER_IS_MISSING","ERROR_CODE_WA_TEXT_TOO_LONG","ERROR_CODE_WA_API_UNKNOWN","ERROR_CODE_WA_PAIR_RATE_LIMIT_HIT","ERROR_CODE_WA_GENERIC_USER_ERROR","ERROR_CODE_WA_ACCESS_DENIED","ERROR_CODE_WA_API_PERMISSION_DENIED","ERROR_CODE_WABA_IN_MAINTENANCE","ERROR_CODE_WA_PERMISSION_DENIED","ERROR_CODE_WA_BIZ_ELIGIBILITY_PAYMENT_ISSUE","ERROR_CODE_WA_UNABLE_TO_DELIVER_THE_MESSAGE","ERROR_CODE_WA_TEMPLATE_PARAM_COUNT_MISMATCH","ERROR_CODE_ETA_ACTION_FAILED","ERROR_CODE_ETA_RATE_LIMIT_REACHED","ERROR_CODE_NOT_ELIGIBLE_FOR_DELIVERY","ERROR_CODE_ETA_USAGE_LIMIT_REACHED","ERROR_CODE_VTEX_CONNECTLY_WABA_PROXY_SLEEPS"],"default":"ERROR_CODE_UNSPECIFIED","title":"- ERROR_CODE_UNCONFIRMED_USER: profile service errors, codes 1xxx\n - ERROR_CODE_EVENT_ALREADY_MARKED_MAPPED: room service errors, codes 2xxx\n - ERROR_CODE_PLATFORM_INVOCATION_ERROR: ERROR_CODE_PLATFORM_INVOCATION_ERROR represents an error received when invoking\nan external API.\n - ERROR_CODE_CAMPAIGN_CONFIG_NAME_CONFLICT: campaign service errors, codes 4xxx\n - ERROR_CODE_ASSET_FETCHING_ERROR: asset service errors, codes 5xxx\n - ERROR_CODE_INVALID_SENDER_ID: external webhook service errors, codes 6xxx\n - ERROR_CODE_PHONE_NUMBER_BAD_FORMAT: external API errors, codes 7xxx\n - ERROR_CODE_ETA_ACTION_FAILED: ETA internal errors, codes 8xxx\n - ERROR_CODE_VTEX_CONNECTLY_WABA_PROXY_SLEEPS: VTEX related error codes"},"rpcStatus":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","$ref":"#/components/schemas/protobufAny"}}}},"protobufAny":{"type":"object","properties":{"@type":{"type":"string","description":"A URL/resource name that uniquely identifies the type of the serialized\nprotocol buffer message. This string must contain at least\none \"/\" character. The last segment of the URL's path must represent\nthe fully qualified name of the type (as in\n`path/google.protobuf.Duration`). The name should be in a canonical form\n(e.g., leading \".\" is not accepted).\n\nIn practice, teams usually precompile into the binary all types that they\nexpect it to use in the context of Any. However, for URLs which use the\nscheme `http`, `https`, or no scheme, one can optionally set up a type\nserver that maps type URLs to message definitions as follows:\n\n* If no scheme is provided, `https` is assumed.\n* An HTTP GET on the URL must yield a [google.protobuf.Type][]\n  value in binary format, or produce an error.\n* Applications are allowed to cache lookup results based on the\n  URL, or have them precompiled into a binary to avoid any\n  lookup. Therefore, binary compatibility needs to be preserved\n  on changes to types. (Use versioned type names to manage\n  breaking changes.)\n\nNote: this functionality is not currently available in the official\nprotobuf release, and it is not used for type URLs beginning with\ntype.googleapis.com. As of May 2023, there are no widely used type server\nimplementations and no plans to implement one.\n\nSchemes other than `http`, `https` (or the empty scheme) might be\nused with implementation specific semantics."}},"additionalProperties":{},"description":"`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n    Foo foo = ...;\n    Any any;\n    any.PackFrom(foo);\n    ...\n    if (any.UnpackTo(&foo)) {\n      ...\n    }\n\nExample 2: Pack and unpack a message in Java.\n\n    Foo foo = ...;\n    Any any = Any.pack(foo);\n    ...\n    if (any.is(Foo.class)) {\n      foo = any.unpack(Foo.class);\n    }\n    // or ...\n    if (any.isSameTypeAs(Foo.getDefaultInstance())) {\n      foo = any.unpack(Foo.getDefaultInstance());\n    }\n\n Example 3: Pack and unpack a message in Python.\n\n    foo = Foo(...)\n    any = Any()\n    any.Pack(foo)\n    ...\n    if any.Is(Foo.DESCRIPTOR):\n      any.Unpack(foo)\n      ...\n\n Example 4: Pack and unpack a message in Go\n\n     foo := &pb.Foo{...}\n     any, err := anypb.New(foo)\n     if err != nil {\n       ...\n     }\n     ...\n     foo := &pb.Foo{}\n     if err := any.UnmarshalTo(foo); err != nil {\n       ...\n     }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n    package google.profile;\n    message Person {\n      string first_name = 1;\n      string last_name = 2;\n    }\n\n    {\n      \"@type\": \"type.googleapis.com/google.profile.Person\",\n      \"firstName\": <string>,\n      \"lastName\": <string>\n    }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n    {\n      \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n      \"value\": \"1.212s\"\n    }"},"dtoSendCampaignsInput":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","$ref":"#/components/schemas/campaignCampaignEntry"},"description":"List of campaign entries.","title":"Entries"},"options":{"$ref":"#/components/schemas/dtoSendCampaignsOptions","description":"Options for sending campaigns.","title":"Options"}}},"campaignCampaignEntry":{"type":"object","properties":{"sender":{"type":"string","description":"(Optional): The identifier of the business channel the campaign will be sent from. If not specified the campaign will be sent from the default channel.","title":"Sender"},"client":{"type":"string","description":"(Required): The identifier of the customer the campaign will be sent to.","title":"Client"},"campaignName":{"type":"string","description":"(Required): The identifier of the campaign this entry will be part of.","title":"Campaign Name"},"variables":{"type":"object","description":"(Optional): A json object describing the flow variables and substituted values used in this campaign. Depending on the campaign configuration all required variables must be provided.","title":"Variables"},"campaignVersion":{"type":"string","description":"(Optional): The identifier of the campaign version (sendout) this entry will be part of.","title":"Campaign Version"},"scheduledAt":{"type":"string","format":"date-time","description":"(Disabled - please don't use): A timestamp indicating when the campaign entry should be executed. Follows the ISO 8601 date-time format","title":"Scheduled at"},"callbackData":{"description":"The callback data will be shown in the webhook payload if it's related to this campaign. Caller can put any fields in this object. Maximum size 1024 bytes.","title":"Callback Data"}},"description":"An entry representing a single flow invocation within a campaign sendout.","title":"Campaign Entry","required":["client","campaignName"]},"dtoSendCampaignsOptions":{"type":"object","properties":{"ifVersionUnspecified":{"$ref":"#/components/schemas/campaignUnspecifiedCampaignVersionBehavior","description":"For all entries that do not specify a specific campaignVersion, decide what sendout will be used. Default is reuse_last_active.","title":"Decide behavior when version is unspecified"},"ifDuplicateCheckUnspecified":{"$ref":"#/components/schemas/campaignUnspecifiedDuplicateCheckBehavior","default":"\"allow_one\"","description":"By default, the system prevents sending the same message to a phone number that has already received it. Setting this option to \"allow_multiple\" overrides this, allowing duplicate messages. This is intended for use cases where repeated messages are necessary, such as service alerts.","title":"Duplicate phone number behavior"}}},"campaignUnspecifiedCampaignVersionBehavior":{"type":"string","enum":["reuse_last_active","create_new"],"default":"reuse_last_active","title":"buf:lint:ignore ENUM_VALUE_UPPER_SNAKE_CASE\nbuf:lint:ignore ENUM_VALUE_PREFIX\nbuf:lint:ignore ENUM_ZERO_VALUE_SUFFIX"},"campaignUnspecifiedDuplicateCheckBehavior":{"type":"string","enum":["allow_one","allow_multiple"],"default":"allow_one","title":"buf:lint:ignore ENUM_VALUE_UPPER_SNAKE_CASE\nbuf:lint:ignore ENUM_VALUE_PREFIX\nbuf:lint:ignore ENUM_ZERO_VALUE_SUFFIX"}}},"paths":{"/v1/businesses/{businessId}/send/campaigns":{"post":{"description":"API to send campaigns to multiple recipients.","operationId":"CampaignService_SendCampaigns","responses":{"200":{"description":"Success: Response contains data including a report of the generated sendouts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1SendCampaignsResponse"}}}},"400":{"description":"Error: Request was malformed.","content":{"application/json":{"schema":{}}}},"401":{"description":"Error: Request presented invalid credentials.","content":{"application/json":{"schema":{}}}},"404":{"description":"Error: Request attempted to use a non existing campaign.","content":{"application/json":{"schema":{}}}},"409":{"description":"Error: Request attempted to use a campaign in the wrong state.","content":{"application/json":{"schema":{}}}},"500":{"description":"Error: There was an internal server error.","content":{"application/json":{"schema":{}}}},"default":{"description":"An unexpected error response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/rpcStatus"}}}}},"parameters":[{"name":"businessId","in":"path","required":true,"type":"string"}],"tags":["CampaignService"],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/dtoSendCampaignsInput"}}},"required":true}}}}}
```

## **Campaign Entry**

### Entry Tips

* Ensure each entry in the "entries" array contains valid and unique combinations of client and campaignName/campaignVersion. (see Multiple campaigns if your intent is to broadcast multiple sendouts from the same API call)&#x20;
* Use the "variables" field to customize campaign content or behavior.
* Campaigns must have been finalized from the Connectly UI for successful execution.
* \[Alpha] Schedule individual (or all) entries for the future using the "scheduledAt" field, adhering to the ISO 8601 format.

### Basic entry

This example represents the minimal setup of campaign entry with only the required fields for a campaign that doesn't use any variables.

```json
{
  "client": "+16505551236",
  "campaignName": "campaign_basic"
}
```

Explanation:

* `client`: The identifier of the customer who will receive the campaign (required).
* `campaignName`: The identifier of the campaign this entry is part of (required).

### Entry with variables

This example includes variables for customizing the campaign experience per client. Variables are configured for each campaign from the Connectly UI.

```json
{
  "client": "+16505551237",
  "campaignName": "campaign_with_variables",
  "variables": {
    "username": "JaneDoe",
    "product": "Smart Watch"
  }
}
```

Explanation:

* `client`: The identifier of the customer who will receive the campaign (required).
* `campaignName`: The identifier of the campaign this entry is part of (required).
* `variables`: JSON object describing flow variables and substituted values.

### Options

By default, this API is not allowed to send a campaign to a user more than once. But if you really need to send a campaign to the same group of customers more than once, you can specify the following option.

```json
{
  "options": {
    "if_duplicate_check_unspecified": "allow_multiple"
  },
  "entries": [
    {
      "client": "+14155558234",
      "campaignName": "campaign",
      "variables": {"key": "value"}
    }
  ]
}
```

With `"if_duplicate_check_unspecified": "allow_multiple"` set, the campaign will be sent to the group of customers even they have received the same campaign before.

## **Multiple Campaigns**

This example demonstrates the inclusion of multiple campaigns within a single API request. The API groups campaign entries by the requested campaign name and optionally the campaign version to utilize different sendouts for each combination.

Each campaign entry object should be using a consistent structure, encompassing key details for the campaign configuration:

1. **Sendout A:**

   * Campaign Name: "campaign\_A"
   * Campaign Version: "v1.0"

   All entries using the above information will be sent as part of the sendout corresponding to the version "v1.0" of campaign A.
2. **Sendout B:**

   * Campaign Name: "campaign\_A"

   All entries using the above information will be sent as part of a new sendout or the latest active sendout on campaign A.
3. **Sendout C:**

   * Campaign Name: "campaign\_B"
   * Campaign Version: v1.0

   All entries using the above information will be sent as part of the sendout corresponding to the version "v1.0" of campaign B

The array structure allows for the inclusion of various campaigns in a cohesive and organized manner within a single API request.

thin a single API request.

```json
"entries": [
    {
      "client": "+14155558234",
      "campaignName": "campaign_A",
      "campaignVersion": "v1.0",
      "variables": {"key1": "value1", "key2": "value2"},
    },
    {
      "client": "+14155559345",
      "campaignName": "campaign_A",
      "variables": {"key1": "value3", "key2": "value4"},
    },
    {
      "client": "+14155550456",
      "campaignName": "campaign_B",
      "campaignVersion": "v1.0",
      "variables": {"Date": "value5", "Name": "value6","Price":"value7"},
    }
  ]
```

Explanation:

1. **Entry for Campaign A**:
   * `client`: The identifier of the customer who will receive the campaign.
   * `campaignName`: The identifier of the campaign (campaign\_A).
   * `campaignVersion`: Identifier of the campaign version (v1.0).
   * `variables`: JSON object describing flow variables and substituted values (key1, key2).
2. **Entry for Campaign B**:
   * `client`: The identifier of the customer who will receive the campaign.
   * `campaignName`: The identifier of the campaign (campaign\_A).
   * `variables`: JSON object describing flow variables and substituted values (key1, key2).
3. **Entry for Campaign C**:

   * `client`: The identifier of the customer who will receive the campaign.
   * `campaignName`: The identifier of the campaign (campaign\_B).
   * `variables`: JSON object describing flow variables and substituted values (Date, Name, Price).
   * `campaignVersion`: Identifier of the campaign version (v1.0).

## Response

The API response provides information about the status of a campaign and related details. The response is in JSON format and includes key data points related to the campaign.

The response consists of a JSON object with a "data" array containing campaign information. Below is a breakdown of the key fields:

* **campaignId**: Unique identifier for the campaign.
* **campaignName**: The name of the campaign (e.g., "campaign\_test").
* **campaignVersion**: Version identifier for the campaign.
* **sendoutId**: Unique identifier for the sendout associated with the campaign.
* **status**: The status of the campaign (e.g., "updated", "created").
* **acceptedCount**: Number of accepted responses.
* **rejectedCount**: Number of rejected responses.
* **error**: An optional field indicating any errors encountered during the campaign processing. It is set to `null` if no errors occurred.

**Examples:**

Simple body request:

```json
{
    "entries": [
        {
            "client": "+123456789",
            "campaignName": "campaign_test",
            "variables": {
                "client": "pablo",
                "name": "test2"
            }
        }
    ]
}
```

Response:

```json
{
    "data": [
        {
            "campaignId": "2963626c-90ea-43e5-9b66-4ce70f003fe3",
            "campaignName": "campaignv3",
            "campaignVersion": "018c5c51-8631-28b5-3c81-b70ecf14faef",
            "sendoutId": "183e801b-1438-4177-b283-909135096e69",
            "status": "created",
            "acceptedCount": 1,
            "rejectedCount": 0,
            "error": null
        }
    ]
}
```

If you send the campaign again the status shows as Updated:

```json
{
    "data": [
        {
            "campaignId": "2963626c-90ea-43e5-9b66-4ce70f003fe3",
            "campaignName": "campaignv3",
            "campaignVersion": "018c5c51-8631-28b5-3c81-b70ecf14faef",
            "sendoutId": "183e801b-1438-4177-b283-909135096e69",
            "status": "updated",
            "acceptedCount": 1,
            "rejectedCount": 0,
            "error": null
        }
    ]
}
```

If you send body without entries:

```json
{
    "client": "+123456789",
    "campaignName": "campaignv3",
    "variables": {
        "client": "pablo",
        "name": "test2"
    },
    "campaignVersion": "018c4a55-f3df-580c-1629-602f3b14d190"
}
```

The response its going to be empty too:

```json
{
    "data": []
}
```

If you specify a wrong campaign name:

```json
{
    "entries": [
        {
            "client": "+123456789",
            "campaignName": "campaña",
            "variables": {
                "client": "pablo",
                "name": "test2"
            }
        }
    ]
}
```

You will get the error detail:

```json
{
    "data": [
        {
            "campaignId": null,
            "campaignName": "campaña",
            "campaignVersion": null,
            "sendoutId": null,
            "status": "error",
            "acceptedCount": 0,
            "rejectedCount": 1,
            "error": {
                "message": "Campaign not found",
                "type": "ERROR_TYPE_NOT_FOUND",
                "code": "ERROR_CODE_CAMPAIGN_NOT_FOUND",
                "userTitle": "Campaign not found",
                "userMessage": "Please review the campaign name and/or campaign id."
            }
        }
    ]
}
```

If you specify a wrong campaign version:

```json
{
    "entries": [
        {
            "client": "+123456789",
            "campaignName": "campaignv3",
            "variables": {
                "client": "pablo",
                "name": "test2"
            },
            "campaignVersion": "018c4a55-f3df-580c-1629-602f3b14d190"
        }
    ]
}
```

You will get the error detail:

```json
{
    "data": [
        {
            "campaignId": "2963626c-90ea-43e5-9b66-4ce70f003fe3",
            "campaignName": "campaignv3",
            "campaignVersion": "018c4a55-f3df-580c-1629-602f3b14d190",
            "sendoutId": null,
            "status": "error",
            "acceptedCount": 0,
            "rejectedCount": 1,
            "error": {
                "message": "Campaign version not found",
                "type": "ERROR_TYPE_NOT_FOUND",
                "code": "ERROR_CODE_CAMPAIGN_VERSION_NOT_FOUND",
                "userTitle": "Campaign version not found",
                "userMessage": "Please review the campaign version."
            }
        }
    ]
}
```

If you don't specify all the variables:

```json
{
    "entries": [
        {
            "client": "+123456789",
            "campaignName": "campaignv3",
            "variables": {
                "client": "pablo"
            }
        }
    ]
}
```

You will get the error detail:

```json
{
    "data": [
        {
            "campaignId": "2963626c-90ea-43e5-9b66-4ce70f003fe3",
            "campaignName": "campaignv3",
            "campaignVersion": "018c5c51-8631-28b5-3c81-b70ecf14faef",
            "sendoutId": "183e801b-1438-4177-b283-909135096e69",
            "status": "error",
            "acceptedCount": 0,
            "rejectedCount": 1,
            "error": {
                "message": "Campaign entry is invalid",
                "type": "ERROR_TYPE_INVALID_REQUEST",
                "code": "ERROR_CODE_CAMPAIGN_ENTRY_INVALID",
                "userTitle": "Campaign entry is invalid",
                "userMessage": "Please check the inputs to the campaign entry."
            }
        }
    ]
}
```

## **Rate Limiting**

To ensure fair usage and maintain service stability, we have implemented rate limiting for above APIs. This endpoint is limited to 200 requests per second. If the limit is exceeded, the API will return a `429 Too Many Requests` response.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.connectly.ai/campaigns/campaign-sendout/send-campaigns.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
