MeyktAPI Documentation
OpenAPI specllms-full.txtDashboard
  • Overview
  • Quickstart
  • Authentication
  • Orders
  • Files
  • Webhooks
  • Errors

Quickstart: your first order in 10 minutes

This page takes you from zero to a personalized order inside Meykt using nothing but curl. The base URL of the API is https://api.meykt.com/v1; every request is authenticated with an API key in the Authorization header. Start in the test environment — test orders are visible in the order list but never reach production.

#Step 1: Create a test key

In the Meykt dashboard go to Integrations → API access → "Create key".

  1. Choose the environment Test. Test keys start with mk_test_, live keys with mk_live_.
  2. Select the scopes you need. For this quickstart: orders:write (send orders), orders:read (read them back), files:write (upload files). There is no scope hierarchy — orders:write does not include orders:read.
  3. Copy the key immediately. The plaintext key is shown exactly once. If you lose it, create a new key and revoke the old one.

Keep the key out of your source code and out of URLs — pass it only as a header.

bash
export MEYKT_API_KEY="mk_test_a1b2c3d4e5f6g7h8i9j0k1l2"

#Step 2: Verify the connection

GET /v1/ping confirms which key and which environment you are actually using. It requires no scope.

bash
curl https://api.meykt.com/v1/ping \
  -H "Authorization: Bearer $MEYKT_API_KEY"

Response 200:

json
{
  "data": {
    "organization": { "name": "Musterwerkstatt" },
    "environment": "test",
    "scopes": ["orders:read", "orders:write", "files:write"],
    "key_prefix": "mk_test_a1b2c3",
    "api_version": "v1"
  }
}

Every authenticated response carries the rate limit headers X-RateLimit-Limit: 120, X-RateLimit-Remaining and X-RateLimit-Reset (seconds until the window resets). The limit is 120 requests per minute per key.

If you get 401 with the code invalid_api_key, the header is malformed or the key is unknown, revoked or expired — all four cases return the same code on purpose. See /developers/errors/invalid_api_key.

#Step 3: Send your first order

POST /v1/orders creates an order. external_order_id is your own order number and is the key for duplicate protection.

bash
curl -X POST https://api.meykt.com/v1/orders \
  -H "Authorization: Bearer $MEYKT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "external_order_id": "ORDER-2026-1044",
    "customer": { "name": "Anna Beispiel" },
    "items": [{
      "sku": "BECHER-GROSS",
      "name": "Becher gross",
      "quantity": 2,
      "personalization": { "gravur": "Alles Gute", "name": "Anna" }
    }]
  }'

Response 201:

json
{
  "data": {
    "order": {
      "id": "8f2c1d0a-6b44-4c11-9a3e-1f0c9d7a5b21",
      "external_order_id": "ORDER-2026-1044",
      "order_number": "ORDER-2026-1044",
      "status": "pending",
      "is_test": true,
      "currency": null,
      "total_amount": null,
      "ordered_at": "2026-08-07T09:12:04.311Z",
      "created_at": "2026-08-07T09:12:44.512Z",
      "updated_at": "2026-08-07T09:12:44.512Z",
      "customer": { "name": "Anna Beispiel", "email": null, "phone": null },
      "items": [
        {
          "id": "b7413f52-0e9a-4d77-8c62-2a5f6c31d904",
          "sku": "BECHER-GROSS",
          "name": "Becher gross",
          "quantity": 2,
          "price": null,
          "product_linked": false,
          "production_status": null,
          "personalization": { "gravur": "Alles Gute", "name": "Anna" },
          "files": []
        }
      ]
    },
    "warnings": [
      {
        "code": "item_product_unmatched",
        "field": "items[0].sku",
        "value": "BECHER-GROSS",
        "message": "SKU \"BECHER-GROSS\" is not linked to any product yet. The order was accepted; link it in the dashboard under Products → assignment queue."
      }
    ]
  }
}

Two things to note:

  • Warnings are not errors. product_linked: false plus item_product_unmatched means Meykt does not know that SKU yet. The order was still accepted. Link the SKU once in the dashboard under Products → assignment queue; from then on it matches automatically.
  • Orders are all-or-nothing. If any item is invalid, the whole order is rejected with 422 validation_failed and nothing is created. The response lists *all* field errors at once, with dot-notation paths such as items.0.quantity. See /developers/errors/validation_failed.

#Step 4: Check the order in the dashboard

Open Orders in the dashboard. The new row carries the Test badge. Open it: customer, quantities, the personalization fields and any attached files are all there.

Test orders behave differently from live orders on purpose:

  • They appear only in the order list — not on the dashboard home, not in statistics, not in billing counters.
  • They never start production and never trigger workflows or webhooks.
  • Test and live are separate numbering spaces: ORDER-2026-1044 used in test does not block the same number in live.

#Step 5: Retry the same request

Send the exact same request from step 3 again. You get 200 — not a duplicate, not a 409.

bash
curl -X POST https://api.meykt.com/v1/orders \
  -H "Authorization: Bearer $MEYKT_API_KEY" \
  -H "Content-Type: application/json" \
  -d @order.json

The body has the same shape as in step 3; data.order.id is identical and data.warnings is empty (the warning was reported when the order was first created). Fields are omitted below for brevity:

json
{
  "data": {
    "order": {
      "id": "8f2c1d0a-6b44-4c11-9a3e-1f0c9d7a5b21",
      "external_order_id": "ORDER-2026-1044",
      "status": "pending",
      "is_test": true
    },
    "warnings": []
  }
}

This is what makes retries safe: after a timeout or a dropped connection, resend the identical request. Same external_order_id and same content → the existing order is returned with 200.

Same external_order_id but different content → 409 order_already_exists_with_different_content. Orders are never overwritten through the API. Do not invent a new order number to work around this — use a new external_order_id only for a genuinely new order, and change existing orders in the dashboard. There is no endpoint for updating an order that was already sent. See /developers/errors/order_already_exists_with_different_content.

#Step 6: Go live

  1. Create a second key in Integrations → API access, this time with the environment Live (prefix mk_live_), with the same scopes.
  2. Replace the key in your system. Nothing else changes: same base URL, same paths, same request bodies.
  3. Verify with GET /v1/ping that the response now says "environment": "live".

From that point on, orders you send are real: they start production, appear in statistics, trigger automation workflows and, if you have registered endpoints, emit the order.received webhook.

bash
curl https://api.meykt.com/v1/ping \
  -H "Authorization: Bearer mk_live_YOUR_KEY"

Keep both keys. The test key stays useful for every future change to your integration — you can rehearse the full flow without touching the shop floor.

#Next steps

  • Authentication — key format, scopes, rate limits, test vs. live.
  • Orders — full field reference, limits (max. 200 items, quantity 1–10,000, max. 50 personalization fields per item), listing with updated_since and cursor paging.
  • Files — the two-step upload: POST /v1/uploads, then PUT the file content to the returned upload_url, then reference the upload_id in items[].files.
  • Webhooks — event types, signature verification, retries. There is deliberately no "shipped" event, because Meykt has no shipping flow. If you cannot expose a public endpoint, poll GET /v1/orders?updated_since=… instead — it is a fully supported path.
  • Error reference — every stable error code with cause and fix. Each API error response also carries a doc_url pointing directly at the matching page.
  • OpenAPI specification — the machine-readable source; generate a client from it instead of transcribing endpoints.

Machine-readable version of this page: https://www.meykt.com/developers/quickstart.md

On this page

  • Step 1: Create a test key
  • Step 2: Verify the connection
  • Step 3: Send your first order
  • Step 4: Check the order in the dashboard
  • Step 5: Retry the same request
  • Step 6: Go live
  • Next steps

Base URL https://api.meykt.com/v1 · Machine-readable: openapi.json · llms-full.txt

Imprint · Privacy · Terms