Skip to content

Upload a campaign's contract

Uploads the contract creators sign for one campaign, replacing the one it has. Only a draft or paused campaign takes one, as in the dashboard. contractBase64 is the PDF as standard base64, at most 4,300,000 characters (a PDF of about 3.2MB). The dashboard takes a contract up to 4MB; upload a larger one there.

POST/v1/campaigns/{campaignId}/contract
  • Scopecampaigns:write
  • Write
  • Safe to retry
  • MCP toolscouty_upload_campaign_contract

Markdown version for your agent

Authorization

Send a Scouty token as a bearer token in the Authorization header. The token needs the campaigns:write scope, or the call answers 403 insufficient_scope. Tokens and scopes

Authorization: Bearer $SCOUTY_TOKEN

Path parameters

NameTypeRequiredDescription
campaignIdintegerRequired

The campaign the contract is for.

Headers

NameTypeRequiredDescription
Idempotency-KeystringOptional

The same key the body's idempotencyKey carries. Send one or the other, or both with the same value.

Body parameters

A JSON object, sent with Content-Type: application/json.

NameTypeRequiredDescription
idempotencyKeystringRequired

A key you choose for this call, 8 to 128 characters of letters, digits, dot, underscore, colon or hyphen. Sending the same key with the same arguments replays the first answer and changes nothing, so a retry after a timeout is safe.

contractBase64stringRequired

The contract, a PDF, as standard base64 with no data: prefix.

Details

scouty_upload_campaign_contract does what the contract field on a campaign does in your dashboard. It replaces the campaign's contract, and only while the campaign is a draft or paused. It does not fill the campaign in from the contract, and it does not change whether creators have to sign it.

The file goes in the JSON body as contractBase64: the PDF as standard base64, with no line breaks and no data: prefix. The field takes at most 4,300,000 characters, which is a PDF of about 3.2 MB. The dashboard takes a contract up to 4 MB, so upload a larger one there. Scouty reads the type from the file itself, so a file that does not start with %PDF- is refused.

json

{ "status": "uploaded", "campaignId": 212 }

On a live campaign:

json

{ "status": "refused", "rule": "campaign_state",
  "message": "This campaign is published, so its details and terms are locked. Ask Scout to pause it and they open again." }

Errors

A refusal answers { "error": { "code", "message" } }. Branch on code; the message is for a person. Every error and its fix

Statuserror.codeMeaning
400 Bad Requestinvalid_requestThe request was not the shape this capability takes, or its body was not JSON.
401 Unauthorizedmissing_token invalid_token token_revoked token_expired token_orphanedNo token, or one that is not recognized, revoked or expired.
403 Forbiddeninsufficient_scope wrong_principalThe token does not carry the scope this capability needs.
404 Not Foundnot_foundNo such route, or no such campaign for this client.
409 Conflictidempotency_conflictThat idempotency key was already used for a different request. Nothing was changed.
429 Too Many Requestsrate_limitedToo many requests this minute. Retry-After says how long is left.