Send matched views
Sends ad views that a partner, such as a clean room or an ad platform's matched export, has tied to the orders they led to.
https://mta.growthdept.ai/api/v1/viewsRequest#
curl -X POST "https://mta.growthdept.ai/api/v1/views" \
-H "Authorization: $MTA_API_KEY" \
-H "Data-Client-ID: $MTA_BRAND_ID" \
-H "Content-Type: application/json" \
-d '{
"views": [
{
"platform": "fb",
"campaign_id": "120200000000100",
"adset_id": "120200000000200",
"ad_id": "120200000000301",
"viewed_at": "2026-11-02T14:03:11Z",
"order_id": "6012345678901"
},
{
"platform": "tiktok",
"campaign_id": "1800000000000100",
"viewed_at": "2026-11-02T15:40:00-08:00",
"email_sha256": "6a6c26195c3682faa816966af789717c3bfa834eee6c599d667d2b3429c27cfd"
}
],
"coverage": [{ "platform": "fb", "from": "2026-11-01", "to": "2026-11-02" }]
}'Response#
{
"message": "Views stored",
"batch_id": "5b1f8e2a-6c3d-4e7f-9a0b-1c2d3e4f5a6b",
"count": 2,
"matched": 2,
"replaced": 0,
"coverage": [
{
"platform": "fb",
"from": "2026-11-01",
"to": "2026-11-02",
"declared": true
}
]
}Authentication#
Send the API key in Authorization and the brand id in Data-Client-ID. The key needs the views:write scope.
A new key gets views:write only when someone ticks it, since a key that sends partner views is made for that partner.
| Header | Type | Description |
|---|---|---|
Authorizationrequired | string | The API key. See Authentication. |
Data-Client-IDrequired | uuid | The brand id. |
Content-Type | string | application/json. |
Body#
Either a JSON array of 1 to 10,000 views, or an object with views (up to 10,000) and coverage (up to 50 ranges); the object needs at least one of either. At most 20 MB. Each view needs exactly one of order_id, email_sha256 and email, and a field this table does not list is refused.
| Field | Type | Description |
|---|---|---|
platformrequired | string | A lower-case platform key: fb, tiktok, snapchat, pinterest, google, applovin and so on. |
campaign_required | string | The platform's campaign id, up to 200 characters. |
adset_ | string | The ad set (ad group) and ad ids, where the partner has them. |
viewed_required | string (date-time) | When the view happened: ISO 8601 with an offset or Z. |
order_one of three | string | The store's order id. Shopify gids (gid://shopify/Order/… and gid://shopify/OrderIdentity/…) are read as the number, and an order name such as #1001 matches too. |
email_one of three | string | The SHA-256 hex digest of the buyer's email, trimmed and lower-cased. |
emailone of three | string | The buyer's email, up to 320 characters. It is hashed on arrival and never stored or logged; prefer email_sha256. |
coverage[].required | string | The platform the range is complete for. |
coverage[].required | string (date) | The first and last view dates of the range, in the brand's time zone. At most 400 days, and from not after to. |
Response fields#
| Field | Type | Description |
|---|---|---|
batch_ | string (uuid) | The id of this delivery. |
count | integer | Views stored. A view sent twice, with the same platform, order key, time and ad, is stored once. |
matched | integer | Of the views sent, those that name an order MTA has now. Orders that arrive later are matched when they do. |
replaced | integer | Stored views removed because a coverage range replaced them. |
coverage | array | The ranges this request declared, each with declared: true. |
Status codes#
| Status | Meaning | Body |
|---|---|---|
| 200 | The views were stored. | |
| 400 | The body is not valid. issues names the path and the rule for the first 50 problems, never the value, since values can hold email addresses. | {
"detail": "invalid input",
"error": "invalid input",
"issues": [
{
"path": "views.0",
"message": "give exactly one of order_id, email_sha256 or email"
}
]
} |
| 401 | No key, an unknown or revoked key, or a key that belongs to another brand than Data-Client-ID. A key with the right brand but without views:write gets 403 instead. | {
"detail": "unauthenticated: send the API key in Authorization and the brand id in Data-Client-ID",
"error": "unauthenticated: send the API key in Authorization and the brand id in Data-Client-ID"
} |
| 403 | The key is valid but lacks views:write. | {
"detail": "this API key lacks the views:write scope",
"error": "this API key lacks the views:write scope"
} |
| 413 | The body is over 20 MB. Send fewer views per request. | {
"detail": "body over 20 MB; send fewer views per request",
"error": "body over 20 MB; send fewer views per request"
} |
| 500 | Something failed on our side. Send the same request again later; views upsert, so a retry is safe. | { "detail": "Internal server error.", "error": "Internal server error." } |
What MTA does with the views#
On the days a platform's views cover, Clicks + Deterministic Views credits that platform from these views, order by order, instead of from its daily view-through counts. A view counts when it came at most 24 hours before the order. A view within 30 seconds of a paid click on the same platform is that click. Paid clicks and views share the order, ahead of unpaid touches such as Direct and email.
Attribution models explains the view models.
Coverage#
A coverage range says the request is the platform's complete set of views for those dates. The views stored for that platform on those dates are replaced by the ones in the request, which may be none.
Without coverage, views are added, and the dates they fall on count as covered. On a covered date the platform's daily counts are not used, so declare only dates the partner's data is complete for.
Matching views to orders#
An email, raw or hashed, becomes a key only this brand's data can match, and the address is discarded. An email view therefore matches only orders that arrived with an email, which today means orders sent to Send orders with customer_email or hashed_customer_email. MTA does not read customer emails from Shopify, so for Shopify stores send order_id.
MTA tracks, per platform, the share of the last 30 days' views that name an order it has, leaving out the last two days while their orders arrive. Below 80%, order-matched credit is missing orders. The usual cause is a purchase event that sends something other than the store's order id.
Questions about the API: support@growthdept.ai.