Scope3 Media Billing API
The Media Billing API from Scope3 — 5 operation(s) for media billing.
The Media Billing API from Scope3 — 5 operation(s) for media billing.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/scope3-media-billing-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
openapi: 3.2.0
info:
title: Scope3 Buyer Media Billing API
version: 2.0.0
description: 'REST API for advertisers to manage advertisers, campaigns, and reporting.
## Authentication
All endpoints require a Bearer token in the Authorization header:
```
Authorization: Bearer your-api-key
```
## Base URL
`https://api.interchange.io/api/v2/buyer`
## For AI Agents
AI agents can use the MCP endpoint at `/mcp/v2/buyer` with three tools:
- `initialize`: Start an MCP session
- `api_call`: Make REST API calls
- `ask_about_capability`: Learn about API features'
servers:
- url: https://api.interchange.io/api/v2/buyer
description: Production server
tags:
- name: Media Billing
paths:
/billing/media-entities:
servers:
- url: https://api.interchange.io/api/v2
description: Production server
get:
operationId: listMediaBillingEntities
summary: List media billing entities
description: List the org's media billing entities — the legal entities Scope3 invoices for media spend.
tags:
- Media Billing
security:
- bearerAuth: []
responses:
'200':
description: List media billing entities
content:
application/json:
schema:
$ref: '#/components/schemas/ListMediaBillingEntitiesResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
post:
operationId: createMediaBillingEntity
summary: Create media billing entity (admin)
description: Create a media billing entity. An org's FIRST entity always becomes PRIMARY (the mandatory backstop every media-transacting org must have) regardless of `isPrimary`. Admin-only.
tags:
- Media Billing
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateMediaBillingEntityBody'
responses:
'200':
description: Create media billing entity (admin)
content:
application/json:
schema:
$ref: '#/components/schemas/CreateMediaBillingEntityResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ACCESS_DENIED (not an account admin).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: CONFLICT (an entity with this name and currency already exists).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/billing/media-entities/{entityId}:
servers:
- url: https://api.interchange.io/api/v2
description: Production server
put:
operationId: updateMediaBillingEntity
summary: Update media billing entity (admin)
description: 'Update fields on an existing media billing entity. Setting `isPrimary: false` on the current primary is refused unless another entity is promoted in its place — an org always has exactly one primary once it has any entity. Admin-only.'
tags:
- Media Billing
security:
- bearerAuth: []
parameters:
- in: path
name: entityId
schema:
description: Surrogate id of the media billing entity.
anyOf:
- type: number
- type: string
required: true
description: Surrogate id of the media billing entity.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
entityName:
description: Legal name of the media billing entity (e.g. "WPP South Africa (Pty) Ltd").
type: string
minLength: 1
maxLength: 255
countryCode:
description: Country of the billing entity, as an ISO 3166-1 alpha-2 code. Metadata only — drives tax treatment and bank/address formatting, never invoice routing (money-streams.md §6.4).
example: US
type: string
pattern: ^[A-Z]{2}$
currency:
description: ISO 4217 currency code
example: USD
type: string
pattern: ^[A-Z]{3}$
billingEmails:
description: Invoicing contact email(s) for this entity. At least one is required.
minItems: 1
maxItems: 20
type: array
items:
type: string
format: email
pattern: ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
addressLine1:
description: Entity street address, line 1.
type: string
minLength: 1
maxLength: 255
addressLine2:
description: Entity street address, line 2 (optional).
type: string
maxLength: 255
city:
description: Entity city.
type: string
minLength: 1
maxLength: 128
state:
description: Entity state/province/region (optional).
type: string
maxLength: 128
postalCode:
description: Entity postal/ZIP code.
type: string
minLength: 1
maxLength: 32
taxId:
description: Tax identifier for this entity (e.g. VAT number, EIN), when applicable.
type: string
maxLength: 64
isPrimary:
description: Set true to promote this entity to PRIMARY (demoting any other primary entity in the same transaction), or false to demote it. Demoting the current primary is refused unless another entity is promoted in its place — an org always has exactly one primary once it has any entity.
type: boolean
responses:
'200':
description: Update media billing entity (admin)
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateMediaBillingEntityResponse'
'400':
description: VALIDATION_ERROR (demoting the primary without a replacement).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ACCESS_DENIED (not an account admin).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: NOT_FOUND (no such entity in this organization).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: CONFLICT (renaming onto an existing name/currency pair).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
delete:
operationId: deleteMediaBillingEntity
summary: Delete media billing entity (admin)
description: Delete a media billing entity. Refused while the entity has advertiser or account attachments — remove those first. Deleting the primary entity auto-promotes the oldest remaining entity, when one exists. Admin-only.
tags:
- Media Billing
security:
- bearerAuth: []
parameters:
- in: path
name: entityId
schema:
description: Surrogate id of the media billing entity.
anyOf:
- type: number
- type: string
required: true
description: Surrogate id of the media billing entity.
responses:
'200':
description: Delete media billing entity (admin)
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteMediaBillingEntityResponse'
'400':
description: VALIDATION_ERROR (entity still has attachments).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ACCESS_DENIED (not an account admin).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: NOT_FOUND (no such entity in this organization).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/billing/media-entities/attachments:
servers:
- url: https://api.interchange.io/api/v2
description: Production server
get:
operationId: listMediaBillingAttachments
summary: List media billing attachments
description: List the advertiser/account attachments that route the org's media billing entities.
tags:
- Media Billing
security:
- bearerAuth: []
responses:
'200':
description: List media billing attachments
content:
application/json:
schema:
$ref: '#/components/schemas/ListMediaBillingAttachmentsResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
post:
operationId: createMediaBillingAttachment
summary: Attach media billing entity (admin)
description: Attach a media billing entity to an advertiser or an account (child customer) — exactly one of advertiserId/childCustomerId. Refused when the org has zero media billing entities (create one first; the org backstop is mandatory). Admin-only.
tags:
- Media Billing
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
entityId:
description: Media billing entity to route this advertiser/account to.
anyOf:
- type: number
- type: string
advertiserId:
description: Advertiser to attach — its media is invoiced to `entityId`. Exactly one of advertiserId/childCustomerId must be set.
anyOf:
- type: integer
format: int64
- type: string
- type: number
childCustomerId:
description: Account (child customer) to attach — its media rolls up to `entityId` for advertisers with no more specific attachment. Exactly one of advertiserId/childCustomerId must be set.
anyOf:
- type: number
- type: string
required:
- entityId
responses:
'200':
description: Attach media billing entity (admin)
content:
application/json:
schema:
$ref: '#/components/schemas/CreateMediaBillingAttachmentResponse'
'400':
description: VALIDATION_ERROR (the org has zero media billing entities).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ACCESS_DENIED (not an account admin, or the advertiser/account is outside the org).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: NOT_FOUND (entityId, or the advertiser, does not exist).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'409':
description: CONFLICT (this advertiser or account is already attached).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/billing/media-entities/attachments/{attachmentId}:
servers:
- url: https://api.interchange.io/api/v2
description: Production server
delete:
operationId: deleteMediaBillingAttachment
summary: Delete media billing attachment (admin)
description: Remove an advertiser/account media billing attachment. Admin-only.
tags:
- Media Billing
security:
- bearerAuth: []
parameters:
- in: path
name: attachmentId
schema:
description: Surrogate id of the media billing attachment.
anyOf:
- type: number
- type: string
required: true
description: Surrogate id of the media billing attachment.
responses:
'200':
description: Delete media billing attachment (admin)
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteMediaBillingAttachmentResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ACCESS_DENIED (not an account admin).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: NOT_FOUND (no such attachment in this organization).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/billing/media-entities/resolve:
servers:
- url: https://api.interchange.io/api/v2
description: Production server
get:
operationId: resolveMediaBillingEntity
summary: Resolve media billing entity
description: 'Answer "who gets this invoice" for an advertiser or account (exactly one of advertiserId/childCustomerId): the advertiser''s own attachment wins, else its owning account''s attachment, else the org PRIMARY entity (the mandatory backstop), else unresolved. Purely structural — no geo/country input.'
tags:
- Media Billing
security:
- bearerAuth: []
parameters:
- in: query
name: advertiserId
schema:
description: Resolve the media billing entity for this advertiser. Exactly one of advertiserId/childCustomerId must be provided.
anyOf:
- type: integer
format: int64
- type: string
- type: number
description: Resolve the media billing entity for this advertiser. Exactly one of advertiserId/childCustomerId must be provided.
- in: query
name: childCustomerId
schema:
description: Resolve the media billing entity for this account (child customer). Exactly one of advertiserId/childCustomerId must be provided.
anyOf:
- type: number
- type: string
description: Resolve the media billing entity for this account (child customer). Exactly one of advertiserId/childCustomerId must be provided.
responses:
'200':
description: Resolve media billing entity
content:
application/json:
schema:
$ref: '#/components/schemas/ResolveMediaBillingEntityResponse'
'400':
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'403':
description: ACCESS_DENIED (the advertiser or account is outside your organization; for accounts this is also returned when the account does not exist, so existence cannot be probed).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: NOT_FOUND (the advertiser does not exist).
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
MediaBillingAttachment:
description: Routes one advertiser or account (child customer) to a media billing entity.
type: object
properties:
id:
description: Attachment ID
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
entityId:
description: Attached entity ID
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
advertiserId:
description: Attached advertiser ID (string — advertiser IDs are 64-bit), or null when this attachment targets an account instead.
type:
- string
- 'null'
childCustomerId:
description: Attached account (child customer) ID, or null when this attachment targets an advertiser instead.
type:
- integer
- 'null'
minimum: -9007199254740991
maximum: 9007199254740991
createdAt:
description: Creation timestamp (ISO 8601)
type: string
format: date-time
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
updatedAt:
description: Last update timestamp (ISO 8601)
type: string
format: date-time
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
required:
- id
- entityId
- advertiserId
- childCustomerId
- createdAt
- updatedAt
additionalProperties: false
ListMediaBillingEntitiesResponse:
description: Media billing entities configured for the org.
type: object
properties:
entities:
type: array
items:
$ref: '#/components/schemas/MediaBillingEntity'
required:
- entities
additionalProperties: false
CreateMediaBillingEntityBody:
description: Create a media billing entity — a legal entity Scope3 invoices for media spend.
type: object
properties:
entityName:
description: Legal name of the media billing entity (e.g. "WPP South Africa (Pty) Ltd").
type: string
minLength: 1
maxLength: 255
countryCode:
description: Country of the billing entity, as an ISO 3166-1 alpha-2 code. Metadata only — drives tax treatment and bank/address formatting, never invoice routing (money-streams.md §6.4).
example: US
type: string
pattern: ^[A-Z]{2}$
currency:
description: ISO 4217 currency code
example: USD
type: string
pattern: ^[A-Z]{3}$
billingEmails:
description: Invoicing contact email(s) for this entity. At least one is required.
minItems: 1
maxItems: 20
type: array
items:
type: string
format: email
pattern: ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
addressLine1:
description: Entity street address, line 1.
type: string
minLength: 1
maxLength: 255
addressLine2:
description: Entity street address, line 2 (optional).
type: string
maxLength: 255
city:
description: Entity city.
type: string
minLength: 1
maxLength: 128
state:
description: Entity state/province/region (optional).
type: string
maxLength: 128
postalCode:
description: Entity postal/ZIP code.
type: string
minLength: 1
maxLength: 32
taxId:
description: Tax identifier for this entity (e.g. VAT number, EIN), when applicable.
type: string
maxLength: 64
isPrimary:
description: Set true to make this the org's PRIMARY media billing entity (the mandatory backstop every media-transacting org must have), demoting any other primary entity. Omit to leave the current primary/non-primary status unchanged. An org's FIRST entity always becomes primary regardless of this field.
type: boolean
required:
- entityName
- countryCode
- currency
- billingEmails
- addressLine1
- city
- postalCode
DeleteMediaBillingAttachmentResponse:
type: object
properties: {}
additionalProperties: false
ErrorResponse:
description: Standard error response
type: object
properties:
data:
type:
- string
- 'null'
enum:
- null
error:
$ref: '#/components/schemas/ApiError'
required:
- data
- error
additionalProperties: false
MediaBillingEntity:
description: A media billing entity — a legal entity Scope3 invoices for media spend.
type: object
properties:
id:
description: Media billing entity ID
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
entityName:
description: Legal name of the media billing entity (e.g. "WPP South Africa (Pty) Ltd").
type: string
minLength: 1
maxLength: 255
countryCode:
description: Country of the billing entity, as an ISO 3166-1 alpha-2 code. Metadata only — drives tax treatment and bank/address formatting, never invoice routing (money-streams.md §6.4).
example: US
type: string
pattern: ^[A-Z]{2}$
currency:
description: ISO 4217 currency code
example: USD
type: string
pattern: ^[A-Z]{3}$
billingEmails:
description: Invoicing contact email(s) for this entity. At least one is required.
minItems: 1
maxItems: 20
type: array
items:
type: string
format: email
pattern: ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
addressLine1:
description: Entity street address, line 1.
type: string
minLength: 1
maxLength: 255
addressLine2:
description: Entity street address, line 2 (optional).
type:
- string
- 'null'
maxLength: 255
city:
description: Entity city.
type: string
minLength: 1
maxLength: 128
state:
description: Entity state/province/region (optional).
type:
- string
- 'null'
maxLength: 128
postalCode:
description: Entity postal/ZIP code.
type: string
minLength: 1
maxLength: 32
taxId:
description: Tax identifier for this entity (e.g. VAT number, EIN), when applicable.
type:
- string
- 'null'
maxLength: 64
isPrimary:
description: Whether this is the org's PRIMARY media billing entity — the mandatory backstop used when no advertiser or account attachment matches. At most one entity per org is primary.
type: boolean
createdAt:
description: Creation timestamp (ISO 8601)
type: string
format: date-time
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
updatedAt:
description: Last update timestamp (ISO 8601)
type: string
format: date-time
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$
required:
- id
- entityName
- countryCode
- currency
- billingEmails
- addressLine1
- city
- postalCode
- isPrimary
- createdAt
- updatedAt
additionalProperties: false
ListMediaBillingAttachmentsResponse:
description: Media billing attachments configured for the org.
type: object
properties:
attachments:
type: array
items:
$ref: '#/components/schemas/MediaBillingAttachment'
required:
- attachments
additionalProperties: false
CreateMediaBillingAttachmentResponse:
type: object
properties:
attachment:
$ref: '#/components/schemas/MediaBillingAttachment'
required:
- attachment
additionalProperties: false
ResolveMediaBillingEntityResponse:
description: 'Answers "who gets this invoice" for an advertiser or account: the resolved media billing entity and which level of the hierarchy it came from.'
type: object
properties:
entity:
description: The resolved media billing entity, or null when the org has no media billing entity at all (not even a primary backstop).
allOf:
- $ref: '#/components/schemas/MediaBillingEntity'
resolvedVia:
description: '"advertiser" (the advertiser has its own attachment), "account" (its owning account does), "org" (the org primary/backstop), or "none" (the org has no entity yet).'
type: string
enum:
- advertiser
- account
- org
- none
required:
- entity
- resolvedVia
additionalProperties: false
ApiError:
description: Structured error object
type: object
properties:
code:
description: Machine-readable error code
type: string
message:
description: Human-readable error message
type: string
field:
description: Field path associated with the error
type: string
details:
description: Additional error context
type: object
additionalProperties: {}
required:
- code
- message
additionalProperties: false
UpdateMediaBillingEntityResponse:
type: object
properties:
entity:
$ref: '#/components/schemas/MediaBillingEntity'
required:
- entity
additionalProperties: false
DeleteMediaBillingEntityResponse:
type: object
properties: {}
additionalProperties: false
CreateMediaBillingEntityResponse:
type: object
properties:
entity:
$ref: '#/components/schemas/MediaBillingEntity'
required:
- entity
additionalProperties: false
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: API key or access token