Guide
Create your first digital business card
The whole workflow, not just the endpoint: what a card is, which fields it takes, the request that creates one, and how to check the result a real person will see.
What a digital business card is
A digital business card is a public web page for one person. It shows who they are and how to reach them, and it has a button that saves them to the visitor’s phone contacts. It lives at its own address, such as https://qrbold.com/c/ada-lovelace, and comes with a QR code that opens that address.
A card is made of two parts, and the API treats them differently:
- Data: the person’s name, title, company, photo, emails, phones, links, address and optional richer sections such as a gallery or testimonials. The API sets and changes this.
- Design: the layout, colours and which blocks appear. The API does not edit this. A card copies its design from a template when it is created, and after that the design is changed in the dashboard.
- What is it?
- A public profile page for one person, with a save-to-contacts button and its own QR code.
- Why would I use it?
- To give employees, sales reps or customers a card without anyone filling in a form by hand.
- What do I need first?
- An API key with
cards:write. Optionally, a template designed in the dashboard. - Which endpoint do I use?
POST /cardswith the person’s data.- What result should I expect?
- A card object with a permanent id and a public url that opens immediately.
The workflow
Pick a template
Optional. GET /templates
Prepare the data
The fields object
Create
POST /cards
Save the id
From the response
Open the url
What people will see
- AuthenticateSend your key in the Authorization header.
- Choose a template, or decide not toA template is optional.
- Prepare the card dataBuild the fields object.
- Send the create requestPOST /cards.
- Check the response201, and paused is false.
- Save the card idYou need it for every later call.
- Retrieve the cardConfirm it reads back as you expect.
- Find the public URLIt is the url field. Nothing to construct.
- Get the QR codeDownload the image with the card id.
- Open the card and check itOn a phone, signed out.
Choose a template
A template is optional. Leave templateId out and the card gets QRBold’s default starter design, with no rules about which fields you may set. That is the fastest way to a first card.
Use a template when every card should share your company’s design. Templates are built in the dashboard under Digital business cards → Templates; the API cannot create them. To find the id of one:
curl "https://api.qrbold.com/api/public/v1/templates" \
-H "Authorization: Bearer $QRBOLD_API_KEY"{
"object": "list",
"data": [
{
"object": "card_template",
"id": "cmf3k1p7d0002",
"name": "Company standard",
"policy": {
"theme": "locked",
"blocks": "reorder_only",
"fields": {
"company": {
"mode": "locked",
"value": "Analytical Engines Ltd"
},
"firstName": {
"mode": "required"
}
}
},
"createdAt": "2026-09-01T08:00:00.000Z",
"updatedAt": "2026-09-20T14:12:00.000Z"
}
],
"pagination": {
"total": 1,
"limit": 25,
"offset": 0,
"hasMore": false
}
}The id is what you pass as templateId. Any template in your account works with any card; there is no compatibility to check.
What a template’s policy means
policy.fields lists rules for individual fields. Fields that are not listed are free to set.
| Mode | What it means for your request |
|---|---|
locked | The template supplies the value. Do not send this field; sending a different value answers 422. |
hidden | The card does not have this field. Do not send it. |
required | You must send a non-empty value. |
prefilled | The template supplies a default that you may override. |
optional | Send it or not. |
In the example above, company is locked and firstName is required. The server enforces these rules for API requests exactly as it does in the dashboard.
Card fields
All of a person’s data goes in one object called fields. Every field is optional as far as the API is concerned; a field becomes required only when the card’s template says so. In practice, send at least firstName and lastName: they become the card’s name.
Identity
| Name | Type | Required | Description |
|---|---|---|---|
prefix | string | Optional | Up to 20 characters, e.g. "Dr". |
firstName | string | Optional | Up to 200 characters. |
middleName | string | Optional | Up to 200 characters. |
lastName | string | Optional | Up to 200 characters. |
suffix | string | Optional | Up to 20 characters, e.g. "PhD". |
preferredName | string | Optional | The name the person goes by. |
pronouns | string | Optional | Up to 40 characters. |
accreditations | array | Optional | Up to 10 strings of 50 characters, e.g. ["CPA", "MBA"]. |
Role
| Name | Type | Required | Description |
|---|---|---|---|
title | string | Optional | Job title. |
department | string | Optional | Department or team. |
company | string | Optional | Company name. |
Media
| Name | Type | Required | Description |
|---|---|---|---|
photoUrl | string | Optional | A publicly reachable URL of the profile photo. The API takes a link, not a file upload. |
coverUrl | string | Optional | URL of the cover image. |
companyLogoUrl | string | Optional | URL of the company logo. |
bio | string | Optional | Up to 2,000 characters. |
Contact
| Name | Type | Required | Description |
|---|---|---|---|
emails | array | Optional | Up to 10 items of { label, value }. |
phones | array | Optional | Up to 10 items of { label, value }. |
links | array | Optional | Up to 20 items of { type, url, label?, subtitle?, iconUrl?, enabled? }. type is one of website, linkedin, x, instagram, facebook, youtube, github, whatsapp, calendly, tiktok, telegram, custom. |
address | object | Optional | { line1, line2, city, state, postalCode, country }, all optional. |
Rich sections
| Name | Type | Required | Description |
|---|---|---|---|
about | object | Optional | { heading, body, imageUrl, signatureUrl, highlights[], milestones[], stats[] }. |
gallery | array | Optional | Up to 24 items of { url, caption?, ratio? }. |
videos | array | Optional | Up to 12 items of { url, title?, description?, thumbnailUrl?, duration? }. |
team | array | Optional | Up to 24 items of { name, title?, photoUrl?, links? }. |
testimonials | array | Optional | Up to 24 items of { quote, author, authorTitle?, authorPhotoUrl?, rating? } (rating 1 to 5). |
products | array | Optional | Up to 24 items of { name, description?, imageUrl?, price?, category?, ctaLabel?, ctaUrl? }. |
Custom
| Name | Type | Required | Description |
|---|---|---|---|
custom | object | Optional | A flat map of string keys to string values, for fields your template declares. |
- Text limits: short text fields take up to 200 characters, and
bioand descriptions up to 2,000. - URLs can be bare domains.
example.comis accepted as well ashttps://example.com.mailto:andtel:links are accepted too. - Images are links.
photoUrl,coverUrlandcompanyLogoUrlmust point at an image that is already public on the internet. The API has no upload. - Link types:
website,linkedin,x,instagram,facebook,youtube,github,whatsapp,calendly,tiktok,telegram,custom. Usecustomwith alabelfor anything else. - Defaults: a field you leave out is simply absent from the card. Nothing is filled in for you unless the template pre-fills or locks it.
- Plans: no field is restricted to a particular plan. Plans limit how many cards an account may have, not what a card contains.
Create the card
/cardsThis request creates a complete card for a fictional person. Replace the values with your own, and replace or remove templateId and shortCode.
curl -X POST "https://api.qrbold.com/api/public/v1/cards" \
-H "Authorization: Bearer $QRBOLD_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"name": "Ada Lovelace",
"templateId": "cmf3k1p7d0002",
"shortCode": "ada-lovelace",
"status": "published",
"fields": {
"firstName": "Ada",
"lastName": "Lovelace",
"title": "Head of Engineering",
"company": "Analytical Engines Ltd",
"photoUrl": "https://example.com/photos/ada.jpg",
"companyLogoUrl": "https://example.com/brand/logo.png",
"bio": "Builds calculating machines and the teams around them.",
"emails": [
{
"label": "Work",
"value": "ada@example.com"
}
],
"phones": [
{
"label": "Mobile",
"value": "+44 20 7946 0958"
}
],
"links": [
{
"type": "website",
"url": "example.com"
},
{
"type": "linkedin",
"url": "linkedin.com/in/ada-lovelace"
}
],
"address": {
"city": "London",
"country": "United Kingdom"
}
}
}'The request body, field by field
| Name | Type | Required | Description |
|---|---|---|---|
fields | object | Optional | The person’s data. See the card fields table. Defaults to an empty object, but a template may require some fields. |
name | string | Optional | Label shown in the dashboard, 1 to 200 characters. Default: first + last name. |
templateId | string | Optional | Copies this template’s design onto the card and applies its field rules. Default: the default starter design. |
shortCode | string | Optional | Custom slug for the public URL: letters, numbers and hyphens, up to 100 characters. Default: a random 8-character code. |
status | string | Optional | published marks the card live straight away. draft marks it as not yet released, but its URL still opens for preview, so do not treat a draft as private. One of draft, published. Default: published. |
Headers
Authorization: Bearer YOUR_API_KEY, required.Content-Type: application/json, required.Idempotency-Key, optional but recommended: any unique value, such as a UUID. If the request times out and you send it again with the same key, you get the original response back instead of a second card. See idempotency.
Read the response
Success is 201 Created with the card object:
{
"object": "card",
"id": "cmf3k2a9x0001",
"name": "Ada Lovelace",
"shortCode": "ada-lovelace",
"status": "published",
"url": "https://qrbold.com/c/ada-lovelace",
"vcardUrl": "https://qrbold.com/c/ada-lovelace/vcard",
"templateId": "cmf3k1p7d0002",
"externalId": null,
"paused": false,
"fields": {
"firstName": "Ada",
"lastName": "Lovelace",
"title": "Head of Engineering",
"company": "Analytical Engines Ltd",
"photoUrl": "https://example.com/photos/ada.jpg",
"companyLogoUrl": "https://example.com/brand/logo.png",
"bio": "Builds calculating machines and the teams around them.",
"emails": [
{
"label": "Work",
"value": "ada@example.com"
}
],
"phones": [
{
"label": "Mobile",
"value": "+44 20 7946 0958"
}
],
"links": [
{
"type": "website",
"url": "example.com"
},
{
"type": "linkedin",
"url": "linkedin.com/in/ada-lovelace"
}
],
"address": {
"city": "London",
"country": "United Kingdom"
}
},
"createdAt": "2026-10-09T09:30:00.000Z",
"updatedAt": "2026-10-09T09:30:00.000Z"
}| Field | What it is |
|---|---|
id | Save this. The permanent identifier you pass to every other card endpoint. |
url | The public card page. This is what you share and what the QR code contains. |
vcardUrl | A link that downloads the contact as a .vcf file. Point a “Save contact” button at it. |
shortCode | The last part of url. Yours if you sent one, otherwise random. |
name | The label in the dashboard. Follows the person’s name. |
status | published unless you asked for draft. |
paused | true means the account’s plan does not currently cover this card and its page will not open. |
templateId | The template it was created from, or null. |
externalId | Your own identifier. Only set for cards created through a campaign; null otherwise. |
fields | The data as stored, after the template’s rules were applied. |
createdAt, updatedAt | ISO 8601 timestamps in UTC. |
A card is live when status is published and paused is false. Check both before you print anything.
Common errors
| Status and code | Why | What to do |
|---|---|---|
422 validation_failed | A value has the wrong type, is too long, or is not in an allowed set, such as an unknown link type. | Fix the fields named in error.details. |
422 validation_failed | The template locks or hides a field you sent, or requires one you left out. | Each entry in details has a key and a reason of locked, hidden or required. |
403 limit_exhausted_cards | The account already has as many cards as its plan covers. Nothing was created. | Add cards to the plan, or delete unused ones. |
400 invalid_request | The shortCode you asked for is taken. | Choose another, or omit it. |
400 reserved_short_link | The shortCode is a reserved word such as login. | Choose another. |
404 resource_not_found | The templateId does not exist in this account. | List templates and use a real id. |
A template violation looks like this. Every problem is listed at once:
{
"error": {
"type": "invalid_request",
"code": "validation_failed",
"message": "Some fields could not be saved.",
"details": [
{
"key": "company",
"reason": "locked"
},
{
"key": "firstName",
"reason": "required"
}
]
}
}What happens after creation
| Question | Answer |
|---|---|
| Is it published immediately? | Yes, unless you sent status: "draft". There is no separate publish step. |
| Is any activation needed? | No. The public URL works as soon as the response arrives. |
| How do I get the public URL? | Read url. Do not build it yourself: accounts with a custom domain get that domain in url. |
| Does it have a unique identifier? | Two: the id (for the API) and the shortCode (in the URL). Both are unique. |
| Can I choose the slug? | Yes, with shortCode at creation. See short links. |
| What if the slug is taken? | The request fails with 400 and nothing is created. A slug is never silently changed or suffixed. |
| Does it already have a QR code? | Yes. Every card has one. You only need to download the image. |
| Does it count toward my plan? | Yes. One card uses one card seat until it is deleted. |
Creating a card, publishing it and creating its QR code are therefore one operation in QRBold, not three. The only separate step is downloading the QR image.
Retrieve a card
By id:
GET/cards/:idcurl "https://api.qrbold.com/api/public/v1/cards/cmf3k2a9x0001" \
-H "Authorization: Bearer $QRBOLD_API_KEY"It returns the same card object as creation. If you did not store the id, find the card by name with the list endpoint. search matches part of the name:
curl "https://api.qrbold.com/api/public/v1/cards?search=Lovelace" \
-H "Authorization: Bearer $QRBOLD_API_KEY"Lists are paged, 25 at a time by default. See pagination.
Update a card
/cards/:idSo the safe way to change one thing is read, modify, write:
GET /cards/:idand take itsfields.- Change what you need in that object.
PATCH /cards/:idwith the whole object.
This example changes Ada’s title and keeps everything else:
curl -X PATCH "https://api.qrbold.com/api/public/v1/cards/cmf3k2a9x0001" \
-H "Authorization: Bearer $QRBOLD_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"fields": {
"firstName": "Ada",
"lastName": "Lovelace",
"title": "Chief Technology Officer",
"company": "Analytical Engines Ltd",
"photoUrl": "https://example.com/photos/ada.jpg",
"companyLogoUrl": "https://example.com/brand/logo.png",
"bio": "Builds calculating machines and the teams around them.",
"emails": [
{
"label": "Work",
"value": "ada@example.com"
}
],
"phones": [
{
"label": "Mobile",
"value": "+44 20 7946 0958"
}
],
"links": [
{
"type": "website",
"url": "example.com"
},
{
"type": "linkedin",
"url": "linkedin.com/in/ada-lovelace"
}
],
"address": {
"city": "London",
"country": "United Kingdom"
}
}
}'- The card’s
id,urland QR code do not change. Nothing needs reprinting. - The card’s
namefollows the person’s name automatically. - Only
fieldsandtemplateIdcan be sent. Status, slug and design cannot be changed through the API; an unknown key here answers 422. - The template’s rules apply to updates just as they do to creation.
Delete a card
/cards/:idcurl -X DELETE "https://api.qrbold.com/api/public/v1/cards/cmf3k2a9x0001" \
-H "Authorization: Bearer $QRBOLD_API_KEY"It answers 204 with no body. The card moves to the account’s Trash, and three things follow:
- Its public URL stops opening straight away, and visitors see an “unavailable” page.
- Its QR code stops working too, because the QR code points at that URL. A printed code for a deleted card leads nowhere.
- It can be restored from Trash in the dashboard for 30 days, which brings the URL and the QR code back. The API cannot restore it.
There is no “deactivate” in the card API. To take a card offline without deleting it, pause or unpublish it in the dashboard.
See the result
Open the url from the response, for example https://qrbold.com/c/ada-lovelace, and check:
- The page opens in a private browser window, where you are not signed in to QRBold.
- The name, title, photo and contact details are the ones you sent.
- The save-contact button downloads a contact. You can test the file directly at
vcardUrl. - It reads well on a phone, since that is where almost every visitor will see it.
- The same card appears in the dashboard under Digital business cards.
Next: generate the QR code for this card, using the id you just saved (cmf3k2a9x0001 in these examples).