Personalized MarketingFor business
Personalized Marketing for developers

Real post, from one API call.

Send a bespoke printed card, an A5 postcard flyer or a letter to anyone in the UK — designed (even from their own website), printed and posted for you. Then get every scan, click, lead and sale back as a webhook. Works with any CRM, shop, app or no-code tool.

Quick start

1. In the Studio, save a campaign (your design and message, or "Bespoke for every company"). Its number is your template_id.
2. Copy your API key from API & integrations.
3. Send:

curl https://www.personalizedmarketing.co.uk/api/v1/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": 123,
    "recipient": {
      "name": "Sarah Jones",
      "company": "Brightside Dental",
      "address1": "12 High Street",
      "city": "Guildford",
      "postcode": "GU1 3AA",
      "website": "https://brightsidedental.co.uk",
      "email": "sarah@brightsidedental.co.uk"
    },
    "reference": "crm-contact-8812"
  }'
{
  "ok": true,
  "id": 4512,
  "status": "designing",
  "format": "card",
  "bespoke": true,
  "offer_code": "K7M2QX",
  "page": "https://www.personalizedmarketing.co.uk/b/?t=9fk2ma7q",
  "credits_used": 1
}

That's it — it is designed, printed and posted. Printing and UK postage are included in every credit.

Authentication

Send your key on every request as Authorization: Bearer YOUR_API_KEY. Keep it secret — anyone with it can send post on your account. Make a new key any time in the Studio (old ones stop working at once). Base URL: https://www.personalizedmarketing.co.uk/api/v1

POST/send

Queue one item — or up to 500 with recipients. Each uses one credit (plus any gift); your balance is checked first.

FieldTypeWhat it does
template_idintA saved campaign in your Studio — its design, message, offer, A/B test, gift, follow-up and booking link are all used.
automation_idintOr: an automation (uses its campaign).
designobjectOr: a design right in the request — see Designs.
typestringletter (A4, in an envelope), flyer (A5 postcard, both sides), card (folded, in an envelope) or digital (no post — a personalised image and personal page for your own emails; only name and ideally email are needed). Defaults to the campaign's.
email_itboolDigital only: true and we email each person their design from your company name (replies come to you). Uses 2 digital credits per person.
recipientobjectname*, address1*, address2, city*, postcode*, company, website (for bespoke designs), email (for the follow-up), and any of your own fields — use them in your message as {field_name}. Shopify and HubSpot shapes are understood as they are.
No address? Send just name and email: we email them a picture of their item and ask where to post it. The response has "status": "awaiting_address" and a claim_url; it prints the moment they reply, and unclaimed items are refunded after 21 days.
recipientsarrayUp to 500 recipient objects (each may have its own reference and arrive_on).
arrive_ondateYYYY-MM-DD — we hold it and post it to arrive that day.
referencestringYour own id (CRM contact, order number) — returned on every event.
testbooltrue checks everything (address, do-not-mail list, credits) without sending or charging.
allow_repeatboolWe never post the same person twice from the same campaign unless this is true.

Every address is checked against the national postcode list and your do-not-mail list before anything is printed.

Designs

No saved campaign? Pass a design — we keep and reuse identical designs automatically.

{
  "type": "letter",
  "design": {
    "bespoke": true,
    "purpose": "marketing",
    "brief": "We fit EV chargers for businesses. Offer a free site survey.",
    "headline": "A little something for {company}",
    "offer": "Free site survey this month — quote your code",
    "booking_url": "https://calendly.com/acme/15min",
    "signoff": "Warm wishes,\nThe Acme team"
  },
  "recipient": { "name": "Tom Patel", "company": "Patel & Co", "address1": "5 Mill Lane",
                 "city": "Bristol", "postcode": "BS1 5TR", "website": "https://patelandco.co.uk" }
}
design.What it does
bespoketrue: we read each recipient's website — a realistic photo of their premises (their real building when they show it, smartened up), their logo and colours, their team (with faces: true) — and write each message or letter for them.
purposemarketing, welcome, thankyou or update.
briefWhat you want to say — the AI writes each message from it.
cover_url, messageYour own artwork (https) and message for non-bespoke items. Use {first_name}, {company} or any recipient field.
headline, signoff, colour, logo_url, companyYour branding (defaults come from your Brand kit).
offerPrinted with a unique code per person — track customers won and revenue.
cta_url, cta_label, booking_urlButtons on each person's personal page (behind the QR code).
giftmug or magic_mug — sent with the card, printed with its design.

GET/items/{id}

{
  "id": 4512, "format": "card", "status": "posted", "status_date": "2026-10-23",
  "tracking_url": "https://…", "reference": "crm-contact-8812",
  "recipient": { "name": "Sarah Jones", "company": "Brightside Dental", "postcode": "GU1 3AA" },
  "preview_url": "https://…", "page_url": "https://www.personalizedmarketing.co.uk/b/?t=9fk2ma7q",
  "offer_code": "K7M2QX", "scans": 2, "clicks": 1, "redemptions": 1, "revenue_pence": 12000
}

Statuses: designing → queued → printing / scheduled → posted (or failed, cancelled). GET/items?campaign_id=&limit=&starting_after= lists them. DELETE/items/{id} stops one that hasn't been made yet and refunds the credit.

GET/campaigns · /campaigns/{id} · /me · /automations

Your campaigns (ids to use as template_id), each campaign's live results (posted, scanned, clicks, customers won, revenue, A/B comparison), your credit balance and your automations.

Webhooks

Set your URL in the Studio (API & integrations) or with POST/webhook {"url": "https://…"}. We POST JSON for every event, signed:

X-PM-Event: card.scanned
X-PM-Signature: sha256=<HMAC-SHA256 of the raw body with your signing secret>

{ "type": "card.scanned", "created": "2026-10-24T09:12:03+00:00",
  "data": { "recipient_id": 4512, "campaign_id": 88, "offer_code": "K7M2QX", "scans": 1,
            "recipient": { "name": "Sarah Jones", "company": "Brightside Dental" } } }
EventWhen
item.createdAn item is queued (API, automation or send link).
item.postedPrinted and handed to Royal Mail.
item.digital_readyA digital design is ready: image_url and page_url for your own email.
item.emailedWe emailed the digital design to the person (when email_it is on).
card.scannedSomeone opens their personal page (QR code).
card.clickedThey press your button or "Book a call".
card.team_photoThey put their own team on the card.
lead.createdThey leave their details on their page.
code.redeemedTheir offer code is used (API, Studio or Shopify).
card.review_clickedThey press "Leave a Google review" on their page.
card.repliedThey send you a thank-you card back.
item.claimedSomeone you sent by email gave us their address — it's going to the printer.
item.cancelledNot claimed in time, or they said no thanks (credits refunded).

Answer with any 2xx. Failed deliveries are retried with back-off for about two days. Verify signatures:

$ok = hash_equals("sha256=" . hash_hmac("sha256", file_get_contents("php://input"), $secret),
                    $_SERVER["HTTP_X_PM_SIGNATURE"] ?? "");

GET/leads · /events

Prefer to poll? /leads?since_id= and /events?since_id= return everything after the last id you saw. Add order=desc for the newest 50 first, and /events?type=card.scanned for one kind only. Using Zapier? Our Zapier app does all of this for you.

POST/redeem

curl https://www.personalizedmarketing.co.uk/api/v1/redeem -H "Authorization: Bearer YOUR_API_KEY" -d code=K7M2QX -d value=49.99

Records a customer won (and what they spent) against the person whose card carried that code. Shopify orders that use a code as a discount are recorded automatically through your automation webhook.

No code: one-click links, automations & Zapier

A "Send card" button in any system

https://www.personalizedmarketing.co.uk/send.php?t=123&name={{contact.name}}&company={{company.name}}&address1={{contact.address}}&city={{contact.city}}&postcode={{contact.zip}}&website={{company.domain}}

Add it as a custom link or button in HubSpot, Pipedrive, Salesforce, a Google Sheet or an email. It opens a filled-in form; you press Send.

Automations (Shopify, HubSpot workflows, Zapier, Make)

In the Studio, turn a campaign into an automation and paste its webhook address into Shopify (Order creation / Customer creation), a HubSpot workflow ("Send a webhook"), or a Zapier/Make "Webhooks — POST" step. Every new customer gets their card automatically.

Errors & limits

{ "error": { "type": "no_credits", "message": "Not enough credits — top up in the Studio" } }
HTTPMeaning
400Something's missing or wrong in the request.
401Missing or wrong API key.
402Not enough credits.
404Not found (template, item, code).
422The recipient can't be posted to (bad postcode, on the do-not-mail list, outside the UK).
429More than 120 requests a minute.

Ready to send real post from your code?

Open API & integrations

Questions? Email hello@personalizedmarketing.co.uk.