Tavoittaja API documentation
If there is anything missing from the documentation or you have something to ask, please feel free to contact us via email.
support@prospectum.fi
Changelog
2026-09-24 Added contacts endpoints
2025-11-24 Added with Tracking endpoint
2025-11-07 Added SMS delivery report documentation
2025-09-30 Initial release
Authentication
You can create the Tavoittaja API -authentication key on Tavoittaja account → API. When creating the API key, it is also possible to provide an email address to receive updates on API changes. You are allowed to create multiple API-keys for your account.
Always store your generated API -keys safely! Do not allow public access to your API keys.
Requests
Tavoittaja API uses HTTP requests, which are handled in JSON format.
Endpoint format is https://api2.tavoittaja.fi/api/<resourceName>. Please note that http is not supported. SSL is required with TLS 1.2+ support.
Error response format
All success responses are 2xx others are considered errors.
{
"errors": [
{
"code": 400,
"title": "Error",
"details": "Invalid phone number provided."
}
]
}
Retries
Your system must retry every request with an increasing delay until it gets a 2xx response. Any other status code, a timeout or a network error counts as a failure.
- Increase the delay after each failed attempt, for example 30, 60, 300, 600, 1800, 3600 seconds. Add a small random delay so that many clients don’t retry at the same moment.
- On 429, wait at least the number of seconds in the Retry-After header.
- 400 and 403 errors return the same error until the request or the account is fixed. Log them and alert someone in addition to retrying.
- A timeout, network error, 502 or 504 on a send request can mean the message was accepted anyway. The API doesn’t detect duplicate requests, so a retry can send the message twice. Use a generous client timeout, at least 60 seconds for send requests with many recipients.
Headers
All Tavoittaja API endpoints require headers to be used. Add your API key to Authorization header.
Authorization: upcqg15aygerfvs933n1gbajjjp34kju1c7dr72uqwe1d6duxecfee1hyi50bkyj
Sender names
You need to have you sender name authorized on Tavoittaja to send SMS to Finland. Log in → Account → Sender names → Add sender name. Currently if you haven’t authorized your sender name SMS gets sent with sender name “Tuntematon” in Finland. Later in 2026 SMS with unauthorized names will be blocked completely.
In Finland Traficom has a list of protected sender names. These sender names are blocked on Tavoittaja. If you want to use one of these sender names email to us at support@prospectum.fi
https://www.traficom.fi/fi/viestinta/laajakaista-ja-puhelin/sms-sender-id-tunnus
Tavoittaja contacts
If your Tavoittaja account has contacts we will also link SMS messages to these contacts using phone number. This way you see all SMS sent to contact on Tavoittaja UI.
Phone numbers
Recommended format for phone numbers is E.164 the international format with country code (+358). If other formats are used we will try to convert the phone number to a valid Finnish phone number by adding +358.
Credits
- Credits are charged on your account for each successful recipient. If recipient is rejected you won’t be charged for it.
- Maximum content length is 918 characters.
- Messages that use only the GSM 7-bit character set (letters, digits, common punctuation, Finnish and Swedish letters) are split into segments: up to 160 characters is 1 segment, longer messages are 153 characters per segment. A few characters, such as €, [, ], {, } and , count as two.
- If the content has emojis or other special characters, the message is sent as Unicode: up to 70 characters is 1 segment, longer messages are 67 characters per segment.
Message processing
- A send response with HTTP 200 means the message was accepted and queued. Delivery happens asynchronously. Use Send SMS with tracking to get delivery reports.
- A send request is processed as one unit. If any message in the request is rejected, for example because of an invalid sender, the whole request fails and nothing is sent.
- Messages sent through the API appear in the message history of the Tavoittaja app.
Endpoints
Send SMS
This is recommended way of sending SMS. You may send multiple messages in a single request and / or send the same message to multiple recipients. We are not enforcing any strict limit on how many messages or recipients you may send in each request.
URL
https://api2.tavoittaja.fi/api/sms/send/multiple
HTTP method
POST
Headers
Authorization: {YOUR_TAVOITTAJA_API_KEY}
Parameters
messages (array of objects)
Each object inside the array have following properties:
| Parameter | Type | Description | Required |
|---|---|---|---|
| sender | string(max:16) | Phone number to be used as a sender in international E.164 format (+358) or alphanumeric sender name (max length 11 characters) | Yes |
| receiverPhones | array of strings | Receiver phone numbers in international E.164 format. | Yes |
| content | string(max: 918) | SMS message content. | Yes |
Examples
POST data
{
"messages": [
{
"sender": "PostTest",
"content": "Test message 1.",
"receiverPhones": [
"+35844123123",
"+358111111"
]
},
{
"sender": "PostTest2",
"content": "Test message 2.",
"receiverPhones": [
"+358449876543"
]
}
]
}
Response (HTTP 200)
Recipients with valid phone numbers are added to acceptedRecipients array of objects. Recipients with invalid phone numbers are rejected and added to rejectedRecipients array of strings. No credits will be charged for recipients that are rejected.
{
"messages": [
{
"sender": "PostTest",
"content": "Test message 1.",
"acceptedRecipients": [
{
"smsMessageRecipientID": 101,
"phone": "+35844123123",
"contentCharacterCount": 15,
"segmentCount": 1,
"creditCount": 1
}
],
"rejectedRecipients": [
"+358111111"
],
"smsMessageID": 35
},
{
"sender": "PostTest2",
"content": "Test message 2.",
"acceptedRecipients": [
{
"smsMessageRecipientID": 102,
"phone": "+358449876543",
"contentCharacterCount": 15,
"segmentCount": 1,
"creditCount": 1
}
],
"rejectedRecipients": [],
"smsMessageID": 36
}
]
}
Send SMS with tracking
If you want to track delivery status of your messages you may use this endpoint to set deliveryStatusCallbackUrl. You may send multiple messages in a single request and / or send the same message to multiple recipients. We are not enforcing any strict limit on how many messages or recipients you may send in each request.
With tracking we are calling deliveryStatusCallbackUrl for every status change we receive from operators.
URL
https://api2.tavoittaja.fi/api/sms/send/withTracking
HTTP method
POST
Headers
Authorization: {YOUR_TAVOITTAJA_API_KEY}
Parameters
messages (array of objects)
Each object inside the array have following properties:
| Parameter | Type | Description | Required |
|---|---|---|---|
| sender | string(max:16) | Phone number to be used as a sender in international E.164 format (+358) or alphanumeric sender name (max length 11 characters) | Yes |
| content | string(max: 918) | SMS message content. | Yes |
| deliveryStatusCallbackUrl | string(max: 500) | Your endpoint URL, that is called for each delivery status change. Must be an http or https URL whose host resolves to a public IPv4 address. https is recommended. | Yes |
| receivers | array of objects | Array of receiver object. See receiver structure below. | Yes |
receivers (array of objects)
| Parameter | Type | Description | Required |
|---|---|---|---|
| receiverPhone | string(max:16) | Receiver phone numbers in international E.164 format. | Yes |
| externalID | string(max:50) | Your system ID for the recipient used in tracking. | Yes |
Examples
POST data
{
"messages": [
{
"sender": "PostTest",
"content": "Test message 1.",
"deliveryStatusCallbackUrl": "https://myapi.com/tavoittajacallback",
"receivers": [
{
"receiverPhone": "+35844123123",
"externalID": "YOUR_EXTERNAL_ID"
},
{
"receiverPhone": "+358111111",
"externalID": "YOUR_EXTERNAL_ID_2"
}
]
},
{
"sender": "PostTest2",
"content": "Test message 2.",
"deliveryStatusCallbackUrl": "https://myapi.com/tavoittajacallback",
"receivers": [
{
"receiverPhone": "+358449876543",
"externalID": "YOUR_EXTERNAL_ID_3"
}
]
}
]
}
Response (HTTP 200)
Recipients with valid phone numbers are added to acceptedRecipients array of objects. Recipients with invalid phone numbers are rejected and added to rejectedRecipients array of objects. No credits will be charged for recipients that are rejected.
{
"messages": [
{
"sender": "PostTest",
"content": "Test message 1.",
"acceptedRecipients": [
{
"smsMessageRecipientID": 101,
"phone": "+35844123123",
"contentCharacterCount": 15,
"segmentCount": 1,
"creditCount": 1,
"externalID": "YOUR_EXTERNAL_ID"
}
],
"rejectedRecipients": [
{
"receiverPhone": "+358111111",
"externalID": "YOUR_EXTERNAL_ID_2"
}
],
"smsMessageID": 35
},
{
"sender": "PostTest2",
"content": "Test message 2.",
"acceptedRecipients": [
{
"smsMessageRecipientID": 102,
"phone": "+358449876543",
"contentCharacterCount": 15,
"segmentCount": 1,
"creditCount": 1,
"externalID": "YOUR_EXTERNAL_ID_3"
}
],
"rejectedRecipients": [],
"smsMessageID": 36
}
]
}
Send a single outbound SMS message
Send a single message to a single recipient. This method exists mostly to support some older systems that aren’t capable of modifying headers or can use only GET requests.
URL
https://api2.tavoittaja.fi/api/sms/send/single
HTTP method
GET
Parameters
Url parameters
| Parameter | Type | Description | Required |
|---|---|---|---|
| sender | string(max:16) | Phone number to be used as a sender in international E.164 format (+358) or alphanumeric sender name (max length 11 characters) | Yes |
| receiverPhone | string(max:16) | Receiver phone number in international E.164 format. | Yes |
| content | string(max: 918) | SMS message content. | Yes |
Url encoding
Remember to encode special characters on URLs. eg. + => %2B or space => %20
Examples
GET https://api2.tavoittaja.fi/api/sms/send/single?apiKey=XXX&sender=%2B3581231231&receiverPhone=358441234567&content=Hello%20from%20Tavoittaja
Response (HTTP 200)
{
"smsMessageRecipientID": 111,
"smsMessageID": 46,
"phone": "+358441234567",
"contentCharacterCount": 21,
"segmentCount": 1,
"creditCount": 1
}
Create or update a contact
Bring contacts from your own system to Tavoittaja. Contacts brought in this way can be used normally in the Tavoittaja UI. You may search them, add them to groups and select them as recipients when sending messages.
A single endpoint handles both creating and updating, so your system does not need to know in advance whether the contact already exists. The contact is identified by contactID or phone.
- If contactID is given, that contact is updated. If your account does not have a contact with this contactID you will get an error. You may not create a contact with a contactID of your own choosing.
- If contactID is not given, the contact is searched by phone. If a contact is found it is updated, otherwise a new contact is created.
HTTP 201 is returned when a new contact was created and HTTP 200 when an existing contact was updated.
Only the fields you send are changed. Fields you leave out keep their current values, so you may send partial updates. We recommend storing the contactID from the response in your own system. It is the most reliable way to identify a contact and the only way to change the phone number of a contact later.
URL
https://api2.tavoittaja.fi/api/contacts
HTTP method
POST
Headers
Authorization: {YOUR_TAVOITTAJA_API_KEY}
Parameters
| Parameter | Type | Description | Required |
|---|---|---|---|
| contactID | integer | Tavoittaja ID of the contact to update. Returned in the response when the contact is created. | Yes, if phone is not given |
| phone | string(max:30) | Contact phone number in international E.164 format. Used to find the contact when contactID is not given. | Yes, if contactID is not given |
| string(max:100) | Must be a valid email address with an existing domain. | No | |
| firstName | string(max:100) | No | |
| lastName | string(max:100) | No | |
| company | string(max:100) | No | |
| jobTitle | string(max:100) | No | |
| city | string(max:50) | No | |
| postalCode | string(max:20) | No | |
| postalAddress | string(max:100) | No | |
| description | string(max:1000) | Free text description shown on the contact. | No |
| status | string | active, inactive or blocked. New contacts are created as active. | No |
| customFields | array of objects | Custom field values. See custom field structure below. | No |
| addGroups | array of strings | Names of the groups the contact is added to. See groups below. | No |
| removeGroups | array of strings | Names of the groups the contact is removed from. See groups below. | No |
customFields (array of objects)
Each object inside the array have following properties:
| Parameter | Type | Description | Required |
|---|---|---|---|
| customFieldName | string(max:100) | Name of the custom field. If your account does not have a custom field with this name yet, it is created automatically. | Yes |
| customFieldValue | string(max:10000) | Value saved for this contact. | Yes |
Tavoittaja custom fields are text fields and they are identified by name, so you do not need to know any IDs. Names are matched exactly, so “Asiakasnumero” and “asiakasnumero” are two different custom fields. Only the custom fields you list are changed, any other values the contact already has are left untouched. Leave customFields out entirely if you do not want to touch custom field values.
Groups
Groups are identified by name, so you do not need to know any IDs. Send addGroups and removeGroups as arrays of exact group names.
- addGroups adds the contact to the named groups. If your account does not have a group with this name yet, the group is created automatically. Adding a contact to a group it already belongs to does nothing.
- removeGroups removes the contact from the named groups. Group names that do not exist on your account are ignored, so removing is always safe to repeat.
Group names are matched exactly. Removals are handled before additions, so if you give the same group name in both arrays the contact ends up in the group. Leave both arrays out entirely if you do not want to touch the groups of the contact.
Contact status
Only contacts with the status active are used as recipients when a message is sent. Contacts with the status inactive or blocked are skipped even if they belong to a group that is selected as a recipient.
| Status | Description |
|---|---|
| active | Normal contact. |
| inactive | Contact is not in active use. |
| blocked | Contact has a message ban and must not be contacted. |
Phone numbers
A phone number may be used by only one contact on your account. If you try to change the number of a contact to a number that already belongs to another contact, the request is rejected.
Examples
POST data
{
"phone": "0401231231",
"firstName": "Peter",
"lastName": "Smith",
"company": "Example Ltd",
"customFields": [
{
"customFieldName": "Customer number",
"customFieldValue": "C123"
}
],
"addGroups": [
"VIP"
]
}
Response (HTTP 201)
A new contact was created. The custom field “Customer number” and the group “VIP” did not exist on the account yet, so they were created automatically.
{
"data": {
"contact": {
"contactID": 24,
"accountID": 30,
"createdByUserID": null,
"contactToken": "gxv55t54",
"phone": "+358401231231",
"email": "",
"firstName": "Peter",
"lastName": "Smith",
"company": "Example Ltd",
"jobTitle": "",
"city": "",
"postalCode": "",
"postalAddress": "",
"description": "",
"status": "active",
"createdFrom": "api",
"timeBlocked": null,
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null,
"contactCustomFields": [
{
"contactCustomFieldID": 4,
"customFieldID": 10,
"contactID": 24,
"value": "C123",
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null,
"customField": {
"customFieldID": 10,
"accountID": 30,
"label": "Customer number",
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null
}
}
],
"contactGroups": [
{
"contactGroupID": 8,
"groupID": 20,
"contactID": 24,
"timeCreated": "2026-09-23 09:40:06",
"group": {
"groupID": 20,
"accountID": 30,
"name": "VIP",
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null
}
}
]
}
},
"errors": []
}
POST data (updating by contactID)
{
"contactID": 24,
"status": "inactive",
"firstName": "David",
"customFields": [
{
"customFieldName": "Customer level",
"customFieldValue": "gold"
},
{
"customFieldName": "Customer number",
"customFieldValue": "C123"
}
],
"addGroups": [
"Marketing campaigns"
],
"removeGroups": [
"Newsletters"
]
}
Response (HTTP 200)
The contact is returned in the same format as above. lastName and company were not sent, so they keep their previous values. The contact is added to the group “Marketing campaigns” and removed from the group “Newsletters”, other groups of the contact are left untouched.
POST data (updating by phone number)
{
"phone": "0401231231",
"city": "Tampere"
}
If a contact with this number exists, only city is updated and the response is HTTP 200. If no contact is found, a new contact is created and the response is HTTP 201.
Find a contact
Fetches a single contact. The contact is identified by contactID or phone exactly as when creating or updating. The custom fields and the groups of the contact are included in the response.
URL
https://api2.tavoittaja.fi/api/contacts/findOne
HTTP method
GET
Headers
Authorization: {YOUR_TAVOITTAJA_API_KEY}
Parameters
Url parameters
| Parameter | Type | Description | Required |
|---|---|---|---|
| contactID | integer | Tavoittaja ID of the contact. | Yes, if phone is not given |
| phone | string(max:30) | Phone number of the contact, in international E.164 format. | Yes, if contactID is not given |
Examples
GET https://api2.tavoittaja.fi/api/contacts/findOne?contactID=24
GET https://api2.tavoittaja.fi/api/contacts/findOne?phone=%2B358401231231
Response (HTTP 200)
The contact is returned in the same format as when creating or updating it. If no matching contact is found an error is returned.
Find all contacts
Returns every contact of your account, including the custom fields and the groups of each contact.
This endpoint is rate limited to 5 requests per minute per account. The limit is shared by all api keys of the account. If you exceed it you get HTTP 429 and a Retry-After header telling how many seconds to wait before trying again. Because the response contains every contact you have, we recommend fetching the full list only when you really need it and using the other endpoints for single contacts.
URL
https://api2.tavoittaja.fi/api/contacts
HTTP method
GET
Headers
Authorization: {YOUR_TAVOITTAJA_API_KEY}
Examples
GET https://api2.tavoittaja.fi/api/contacts
Response (HTTP 200)
{
"data": {
"contacts": [
{
"contactID": 24,
"accountID": 30,
"createdByUserID": null,
"contactToken": "gxv55t54",
"phone": "+358401231231",
"email": "",
"firstName": "Mary",
"lastName": "Davidson",
"company": "Tractors Ltd",
"jobTitle": "",
"city": "",
"postalCode": "",
"postalAddress": "",
"description": "",
"status": "active",
"createdFrom": "api",
"timeBlocked": null,
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null,
"contactCustomFields": [
{
"contactCustomFieldID": 4,
"customFieldID": 10,
"contactID": 24,
"value": "C222",
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null,
"customField": {
"customFieldID": 10,
"accountID": 30,
"label": "Customer number",
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null
}
}
],
"contactGroups": [
{
"contactGroupID": 8,
"groupID": 20,
"contactID": 24,
"timeCreated": "2026-09-23 09:40:06",
"group": {
"groupID": 20,
"accountID": 30,
"name": "Marketing campaigns",
"timeCreated": "2026-09-23 09:40:06",
"timeModified": null
}
}
]
},
{
"contactID": 25,
"accountID": 30,
"createdByUserID": null,
"contactToken": "vh9s5ez5",
"phone": "+358447654321",
"email": "",
"firstName": "Carrey",
"lastName": "Customer",
"company": "",
"jobTitle": "",
"city": "",
"postalCode": "",
"postalAddress": "",
"description": "",
"status": "active",
"createdFrom": "api",
"timeBlocked": null,
"timeCreated": "2026-09-23 09:41:12",
"timeModified": null,
"contactCustomFields": [],
"contactGroups": []
}
]
},
"errors": []
}
Delete a contact
Deletes a contact from your account. The contact is identified by contactID or phone exactly as when creating or updating. Deleting a contact also removes it from all groups it belongs to. Messages already sent to the contact remain in your sending history. After a contact has been deleted its phone number is free to be used by a new contact.
URL
https://api2.tavoittaja.fi/api/contacts
HTTP method
DELETE
Headers
Authorization: {YOUR_TAVOITTAJA_API_KEY}
Parameters
| Parameter | Type | Description | Required |
|---|---|---|---|
| contactID | integer | Tavoittaja ID of the contact to delete. | Yes, if phone is not given |
| phone | string(max:30) | Phone number of the contact to delete, in international E.164 format. | Yes, if contactID is not given |
Examples
Request body (JSON)
{
"contactID": 24
}
or
{
"phone": "0401231231"
}
Response (HTTP 204)
A successful delete returns HTTP 204 with an empty response body. If no matching contact is found an error is returned.
Contact endpoint errors
In addition to the general error response format, the contact endpoints may return the following errors.
| Details | Reason |
|---|---|
| Invalid phone number provided. | The given phone number could not be converted to a valid phone number. |
| Contact not found. | Your account does not have a contact matching the given contactID or phone. |
| This phone number already exist on another contact. | Another contact on your account already uses the phone number you tried to save. |
| Too many requests. Please wait a moment and try again. | The rate limit of the find all contacts endpoint was exceeded. This error is returned with HTTP code 429. Wait the number of seconds given in the Retry-After header before trying again. |
Delivery reports
If the deliveryStatusCallbackUrl is posted in your request data, Tavoittaja will use this url to send the delivery status report.
Delivery reports technical information
- Data is posted as JSON. Unescaped unicode characters and slashes are used.
- Request is a POST request.
- Receiving endpoint should respond with HTTP code 204 (any 2xx is accepted too) and empty response body.
- If Tavoittaja does not receive a successful HTTP response (2xx status code) from the receiving server, it will automatically retry the delivery report. The retry mechanism uses an incremental backoff strategy with a maximum of five attempts. The retry intervals are: 1, 2, 5, 10, and 60 minutes.
- Request timeout is set to 10 seconds.
- Delivery reports are not always delivered in chronological order. You may receive 1000 queued before, 1 accepted sometimes. Some operators may deliver them like this.
Examples
Success example
{
"smsMessageRecipientID": 118,
"externalID": "YOUR_EXTERNAL_ID",
"statusCode": 2000,
"statusMessage": "Billed and delivered",
"timeDelivered": "2025-11-07 12:42:23"
}
Failed example
{
"smsMessageRecipientID": 119,
"externalID": "YOUR_EXTERNAL_ID",
"statusCode": 4007,
"statusMessage": "Not delivered",
"timeDelivered": null
}
Explanations
| Field | Description |
|---|---|
| smsMessageRecipientID | Unique ID per recipient. You can use this to identify which recipients delivery status changed. |
| externalID | Your system ID used to recognize recipients. |
| statusCode | Status code that describes current delivery status. |
| statusMessage | Raw operator status message in English. |
| timeDelivered | When message is delivered and status code is 2000. timeDelivered gets set. Otherwise null. This time is reported in UTC in ISO format. e.g. 2026-12-20 13:40:00 |
Status codes
Following codes are considered to be in process: 1, 2, 1000, 1001, 5000
Code 2000 is considered to be delivered successfully.
Any other code is considered error.
| Status code | Description |
|---|---|
| 1 | Accepted |
| 2 | Scheduled |
| 1000 | Queued |
| 1001 | Sent to gateway |
| 2000 | Delivered |
| 3000 | Account validation error |
| 3001 | Configuration error |
| 3002 | Invalid sender |
| 3003 | Sender type not supported |
| 3004 | Invalid recipient |
| 3005 | Destination type not supported |
| 3006 | Encoding not supported |
| 3007 | Invalid message content |
| 3008 | Invalid user data header |
| 3009 | Maximum throttling exceeded |
| 3010 | Validation error |
| 3011 | Quota exceeded |
| 3013 | Country blocked |
| 4000 | Generic error |
| 4001 | Temporary routing error |
| 4002 | Permanent routing error |
| 4003 | Phone number blocked |
| 4004 | Recipient temporarily barred |
| 4005 | Service provider error |
| 4006 | Operation blocked |
| 4007 | Not delivered |
| 4008 | Expired |
| 4009 | Timeout |
| 4010 | Delivery report not supported |
| 4011 | Deleted by operator |
| 5000 | Retried |