API documentation
For agencies and organisations with their own software: send requests directly via the API instead of the form. The same rules apply as in the form; vetted printers and lettershops submit their quotes as usual.
Getting started
- Log in or create an account, then generate a key under API access.
- Send the key in the Authorization header with every call.
- Create a request. It belongs to your account straight away and also shows up under "My requests".
- Base URL
https://mailingbid.com/api/v1- Authentication
Authorization: Bearer mb_live_…- Format
- JSON (UTF-8), dates as YYYY-MM-DD
- Limits
- 120 calls per minute per key; 60 new requests per hour per account
Treat the key like a password: server-side only, never in a browser or an app. You can revoke a key at any time.
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/requests | Create a request |
GET | /api/v1/requests | All requests of your account |
GET | /api/v1/requests/{id} | One request with its parts, countries and published offers |
PATCH | /api/v1/requests/{id} | Add or change a request's details |
GET | /api/v1/catalogue | Accepted values (parts, formats, countries); no key needed |
Create a request
At least one country with a quantity (tranches) and at least one part (positions) are required. Everything else is optional and can be added later.
Without them, the same defaults apply as in the form: a title from the posting date, an offer deadline in 5 working days, and production, lettershop and posting as services. Contact details and language come from your account. The response is 201 with the stored request.
Requests sent through the API are subject to our terms.
curl -X POST https://mailingbid.com/api/v1/requests \
-H "Authorization: Bearer $MAILINGBID_API_KEY" \
-H "Content-Type: application/json" \
--data @anfrage.jsonExample: anfrage.json
{
"title": "Spring mailing 2027",
"defaultPostingDate": "2027-03-12",
"tranches": [
{
"country": "AT",
"quantity": 30000
},
{
"country": "CZ",
"quantity": 10000,
"postProduct": "standard"
}
],
"positions": [
{
"type": "envelope",
"format": "C6/5",
"paperGsm": 80,
"spec": {
"window": "left"
}
},
{
"type": "letter",
"format": "A4",
"colors": "4/4",
"spec": {
"fold": "wrap_dl",
"personalization": "address"
}
},
{
"type": "payment_slip",
"spec": {
"standards": {
"AT": "at_sepa",
"CZ": "cz_pk_a"
},
"execution": "attached"
}
}
],
"serviceScope": [
"production",
"lettershop",
"posting"
],
"contractingParty": "agency",
"onBehalfOf": "Organisation A",
"iso27001Required": false
}Response (shortened)
{
"request": {
"id": 123,
"status": "received",
"title": "…",
"offerDeadline": "2027-01-15",
"serviceScope": ["production", "lettershop", "posting"],
"url": "https://mailingbid.com/anfragen/123",
…
},
"tranches": [{ "id": 401, "country": "AT", "quantity": 30000, … }],
"positions": [{ "id": 901, "type": "envelope", "format": "C6/5", … }],
"offers": [],
"files": [],
"decision": null,
"details": { "editable": true, "lock": null }
}Request fields
| Field | Required | Description |
|---|---|---|
tranches | yes | List of countries with quantities, 1 to 50 entries. |
positions | yes | List of parts, 1 to 30 entries, at least one not supplied by you. |
title | no | Your own title, 3 to 200 characters. |
defaultPostingDate | no | Shared posting date. |
offerDeadline | no | Offers due by; at least 3 working days from today. |
serviceScope | no | Services wanted: production, lettershop, posting. |
postingAt | no | Country of posting, if not always the destination country. |
contractingParty | no | Contracting party: ngo, agency or company. |
onBehalfOf | no | Required for agency: who you are requesting for. Suppliers only see it once the job is awarded. |
paymentTerms | no | Payment terms you want, as free text. |
iso27001Required | no | true: only ask ISO 27001 certified suppliers. |
notes | no | Notes on the job, up to 4,000 characters. Please no addresses or donor data. |
contactName | no | Contact person; default: your account's name. |
contactEmail | no | Contact person's email; default: your account's email. Confirmations always go to your account. |
contactOrganization | no | Organisation; default: from your account. |
contactPhone | no | Phone; default: from your account. |
locale | no | Language of the emails: de, cs or en; default: your account's language. |
Countries and quantities (tranches)
| Field | Description |
|---|---|
country | Destination country, two-letter ISO code (required). |
quantity | Quantity (required). |
postingDate | Own posting date, otherwise the shared one. |
graphicVariants | Number of design variants, default 1. |
postProduct | Postal product; empty: the supplier suggests one. |
code | Your own reference, unique within the request; suppliers don't see it. |
returnAddress | Return address for undeliverables; suppliers only see it once the job is awarded. |
Parts of the mailing (positions)
| Field | Description |
|---|---|
type | Type of part (required), see values below. |
label | Your own label, e.g. "blue pen". |
format | Format from the type's list; custom for your own size. |
formatMm | Only with custom: width×height in mm, e.g. 210x297. |
paperGsm | Paper weight in gsm within the type's range. |
colors | Colours, e.g. 4/4; special for a spot colour. |
piecesPerMailing | Pieces per mailing, default 1. |
suppliedByCustomer | true: you supply this part yourself. |
trancheScope | Only for certain countries: indexes into tranches (from 0); without it the part applies to all. |
details | Further details, up to 2,000 characters. |
spec | Details per type, see values below. Unknown keys are rejected. |
Payment slips have no format, paper or colours: these follow from the country's standard. The server rejects such values.
Retrieve requests and offers
GET /api/v1/requests returns all requests of your account with their status and number of published offers. GET /api/v1/requests/ID returns one request in full.
curl https://mailingbid.com/api/v1/requests \
-H "Authorization: Bearer $MAILINGBID_API_KEY"Offers appear once we have published them: with supplier, covered parts and countries, the execution per part (positionConformity: as requested or deviating, with a description), price lines by type (total price excluding postage or price per part, postage separate), the postage statement (postageStatement: separate or not_offered), total, validity, price adjustment clause, payment terms, what's included and remarks. For older offers positionConformity and postageStatement are null. Amounts are in cents; EUR and CZK are never added together. Several offers from one provider are variants: variantLabel is the name of the alternative (null for the first offer), variantGroup is the same number for all offers of one provider (null for offers we entered ourselves). Only one variant per provider can be chosen in a selection.
Status of a request:
received– receivedin_progress– in progress, offers are being gatheredoffers_available– offers availableclosed– decided
Choosing offers is binding, so it is done in the browser at the request's URL (field url).
Add details
PATCH /api/v1/requests/ID takes the same fields as creating a request, all optional: a missing field stays as it is; null clears it.
curl -X PATCH https://mailingbid.com/api/v1/requests/123 \
-H "Authorization: Bearer $MAILINGBID_API_KEY" \
-H "Content-Type: application/json" \
--data '{ "paymentTerms": "30", "notes": "…" }'tranches and positions are replaced as a whole and always sent together. Existing entries keep their id: send the id to change an entry; without an id a new one is created, and missing ones are deleted.
Changes are possible while the request is received or in progress and no offer has been published; after that the server answers 409 details_locked.
Accepted values
GET /api/v1/catalogue returns the same values as JSON.
type | format | paperGsm | spec |
|---|---|---|---|
envelope · Envelope | DL, C6/5, C6, C5, C4, B4, custom | 70–120 | window: none | left | rightclosure: wet | peel | selfinnerPrint: booleanspecialColor: text |
letter · Letter | A4, A5, custom | 40–400 | pages: one_sided | two_sided | two_sheets | four_pagesfold: wrap_dl | single_a5 | none | crosspersonalization: none | address | variable_text | variable_text_imagespecialColor: text |
payment_slip · Payment slip | – | – | standards: object: country -> standardexecution: attached | separate | qr_onlyprefill: reference | donor | amountqrCode: boolean |
postcard · Postcard / reply card | A6, DL, MAXI, custom | 40–400 | replyMail: booleanfinishing: none | dispersion | uv | cello_matt | cello_glosspersonalization: none | senderspecialColor: text |
certificate · Certificate | A4, A5, custom | 40–400 | finishing: none | embossing | hot_foilpersonalizedName: booleanspecialColor: text |
tax_receipt · Donation receipt | A4, A5 | 40–400 | specialColor: text |
insert · Insert / flyer | DL, A6, A5, custom | 40–400 | fold: none | single | wrap | zigzagspecialColor: text |
promo_item · Promotional item | – | – | article: textlengthMm: numberwidthMm: numberheightMm: numberweightG: numbermaterial: textbranding: none | print_1c | print_4c | engravingpackaging: loose | polybag | gluedsourcing: supplied | sourced |
other · Other | – | – | – |
colors- 4/0, 4/4, 1/0, 1/1, special
serviceScope- production, lettershop, posting
contractingParty- ngo, agency, company
postProduct- standard, sponsoring_mail (AT), info_mail, euro_mail, postaim (IE), charity_acquisition_post (IE), other
spec.standards- at_sepa (AT), at_donation (AT), de_donation (DE), de_sepa (DE), cz_pk_a (CZ), sk_poukaz (SK), qr_only
country- AT, CZ, SK, DE, PL, BE, BG, HR, CY, DK, EE, FI, FR, GR, HU, IE, IT, LV, LT, LU, MT, NL, PT, RO, SI, ES, SE, IS, LI, NO, CH
Errors
Errors come with a matching HTTP status and a stable code in data.code. For validation_error, data.issues names the field that doesn't fit.
{
"statusCode": 400,
"statusMessage": "…",
"data": {
"code": "validation_error",
"issues": { "fieldErrors": { "tranches": ["…"] } }
}
}data.code | Description |
|---|---|
validation_error | A field is missing or has an invalid value (400). |
offer_deadline_too_early | The offer deadline is less than 3 working days away; data.earliest gives the earliest date (400). |
api_key_invalid | The key is missing, wrong or revoked (401). |
forbidden | The request doesn't exist or doesn't belong to your account (403). |
details_locked | The request can no longer be changed (409). |
invalid_details_reference | An id doesn't belong to this request (400). |
body_too_large | The JSON body is larger than 1 MB; data.maxBytes gives the limit (413). |
rate_limited | Too many calls; please try again later (429). |
Good to know
- Upload files (e.g. sample artwork) on the request's details page in the browser.
- You make the binding choice of offer in the browser.
- The confirmation of each request goes to your account's email address, even if you give a different contact address.
- Until the job is awarded, suppliers see neither your name nor your organisation or contact details.
Rather not code? Use the request form.