Free & Fast Shipping On Every Gift
MOATDM Gift Store

For developers

MOATDM partner API

Show MOATDM gifts in your own app or website, priced for wherever your customer is sending to. Every call is a plain HTTPS request with your key, and every answer is JSON.

Base address

https://moatdmgiftstore.com/api/v1

Money

Naira, in kobo (₦1 = 100 kobo)

Format

JSON

Version

1.0.0

Quick start

  1. Get approved

    Apply as a partner. We read every application and email you when it's decided.

  2. Make a test key

    In your partner portal, make a test key and copy it. It's shown once. Keep it in an environment variable, not in your code:

    Terminal
    export MOATDM_API_KEY="mdm_test_…"
  3. Check the key

    This tells you which partner and mode the key belongs to.

    curl https://moatdmgiftstore.com/api/v1/me \
      -H "Authorization: Bearer $MOATDM_API_KEY"
  4. Find a destination, then its products

    Products and prices depend on where the gift is going, so start with GET /destinations and pass a code as destination.

    curl https://moatdmgiftstore.com/api/v1/destinations \
      -H "Authorization: Bearer $MOATDM_API_KEY"
    curl "https://moatdmgiftstore.com/api/v1/products?destination=GB" \
      -H "Authorization: Bearer $MOATDM_API_KEY"

Keys and test mode

Send your key on every call as Authorization: Bearer <key>. A key starts with mdm_test_ or mdm_live_, followed by 32 letters and numbers.

KeyWhat it does
TestReads the real catalogue at your real prices, and spends a play wallet of ₦1,000,000. Nothing is charged and no gift is sent. Use it while you build.
LivePlaces real orders, paid from your wallet. It opens once you accept the reseller agreement in your portal.
Full accessCarries catalog:read, wallet:read and orders:write.
Read onlyCarries catalog:read alone. Right for a price list or product pages.
  • Keep keys on your server. Never put one in a mobile app or a web page, where anyone can read it.
  • We keep only a fingerprint of each key, so a lost key can't be shown again. Make a new one and revoke the old one.
  • Revoking a key in your portal stops it at once. Revoke any key you think has leaked.
  • You can hold up to 10 keys at a time, for example one per server or environment.

Prices and money

Every amount is a whole number of kobo, so there are no rounding surprises: 6000000 is ₦60,000. Prices already include delivery to the destination you asked about.

price_kobo is what you pay, after your tier's discount. shop_price_kobo is what the shop charges a customer. What you charge is yours to set, and the difference is yours to keep. The reseller agreement asks only that you don't advertise a gift below shop_price_kobo.

TierWhat you payWho
StarterShop pricesWhere every partner starts
Growth2% off shop pricesOnce your orders are steady each month
Premier3% off shop pricesFor our biggest partners, with priority support

Orders are prepaid from your naira wallet; there's no credit. Top-ups start at ₦15,000 and go through Paystack, whose fee is yours. A cancelled order is refunded to the wallet.

API reference

Every call below is a GET. Pick the language once and every sample follows it.

Check your key

GET/me

Who the key belongs to, its mode and permissions, and your tier. The quickest way to test a key.

Needs catalog:read, which every key has.

Request

curl https://moatdmgiftstore.com/api/v1/me \
  -H "Authorization: Bearer $MOATDM_API_KEY"

Response · 200

JSON
{
  "partner": {
    "id": "3b0d5f2e-7c41-4a8e-9b6d-2f1e8a7c5d90",
    "business_name": "Kashora",
    "tier": "starter",
    "discount_percent": 0
  },
  "key": {
    "id": "8c2e4a1b-5d3f-4e6a-8b7c-9d0e1f2a3b4c",
    "name": "Backend",
    "mode": "test",
    "prefix": "mdm_test_Ab12Cd",
    "scopes": [
      "catalog:read",
      "wallet:read",
      "orders:write"
    ]
  }
}

Can fail with missing_key, invalid_key, key_revoked, partner_not_active, rate_limited.

List destinations

GET/destinations

Every country MOATDM delivers to, with its ISO code. Use the code as the destination for products.

Needs catalog:read, which every key has.

Request

curl https://moatdmgiftstore.com/api/v1/destinations \
  -H "Authorization: Bearer $MOATDM_API_KEY"

Response · 200

JSON
{
  "data": [
    {
      "code": "GB",
      "name": "United Kingdom",
      "flag": "🇬🇧",
      "currency": "GBP"
    },
    {
      "code": "US",
      "name": "United States",
      "flag": "🇺🇸",
      "currency": "USD"
    }
  ]
}

Can fail with missing_key, invalid_key, rate_limited.

List categories

GET/categories

The shop's categories, in the order the shop shows them.

Needs catalog:read, which every key has.

Request

curl https://moatdmgiftstore.com/api/v1/categories \
  -H "Authorization: Bearer $MOATDM_API_KEY"

Response · 200

JSON
{
  "data": [
    {
      "slug": "flowers",
      "name": "Flowers & Florals",
      "description": "Fresh bouquets and arrangements",
      "image": "https://moatdmgiftstore.com/api/public/img?src=categories%2Fflowers.png&w=800"
    }
  ]
}

Can fail with missing_key, invalid_key, rate_limited.

List products

GET/products

Products that deliver to one country, with your price, photos, options and delivery days. Prices are in kobo (₦1 = 100 kobo) and already include delivery.

Needs catalog:read, which every key has.

Parameters

NameInDescription
destinationrequiredqueryISO country code from GET /destinations.Example: GB
categoryqueryA category slug, to list only that category.Example: flowers
pagequeryPage number, from 1.Example: 1
per_pagequeryProducts per page, 1 to 100. Default 40.Example: 40

Request

curl "https://moatdmgiftstore.com/api/v1/products?destination=GB" \
  -H "Authorization: Bearer $MOATDM_API_KEY"

Response · 200

JSON
{
  "data": [
    {
      "id": "6f1c2a90-3c1e-4c55-9a0b-8b1e2f9d4a11",
      "slug": "fresh-flower-mixed-arrangements",
      "name": "Fresh Flower Mixed Arrangements",
      "tagline": "Seasonal blooms, hand-tied",
      "description": "A hand-tied bouquet of the season's freshest blooms.",
      "category": {
        "slug": "flowers",
        "name": "Flowers & Florals"
      },
      "type": "gift",
      "images": [
        "https://moatdmgiftstore.com/api/public/img?src=products%2Fflowers-mixed.jpg&w=1200"
      ],
      "currency": "NGN",
      "price_kobo": 6000000,
      "shop_price_kobo": 6000000,
      "in_stock": true,
      "variants": [
        {
          "id": "v-small",
          "name": "Small",
          "price_kobo": 6000000,
          "shop_price_kobo": 6000000,
          "in_stock": true
        },
        {
          "id": "v-large",
          "name": "Large",
          "price_kobo": 9000000,
          "shop_price_kobo": 9000000,
          "in_stock": true
        }
      ],
      "delivery": {
        "days_min": 1,
        "days_max": 2
      },
      "gift_message": true
    }
  ],
  "page": 1,
  "per_page": 40,
  "total": 1,
  "has_more": false
}
Every product field
FieldTypeMeaning
idstringThe product's id. It never changes.
slugstringA readable id, also accepted by GET /products/{id}. It can change if we rename the product, so store the id.
namestringThe product's name.
taglinestring | nullOne short line under the name.
descriptionstring | nullA paragraph about the product, in plain text.
categoryobject | nullThe category's slug and name.
type"gift" | "digital"A digital product is delivered by message: no address and no delivery days.
imagesstring[]Full https addresses. The first is the main photo.
currency"NGN"Every price is in naira.
price_kobointegerWhat you pay for this destination, in kobo, after your tier's discount. Delivery is included.
shop_price_kobointegerWhat the shop charges a customer for the same product and destination. The reseller agreement asks you not to advertise below it.
in_stockbooleanWhether it can be ordered now.
variantsobject[]Options such as size, each with its own id, name, prices and stock. When there are variants, order one by its id.
deliveryobject | nulldays_min and days_max: working days to deliver once the order is confirmed. null for digital products.
gift_messagebooleanWhether the order can carry a gift message.

Can fail with invalid_request, destination_not_served, rate_limited.

Get a product

GET/products/{id}

One product by id or slug, priced for a destination, with every variant.

Needs catalog:read, which every key has.

Parameters

NameInDescription
idrequiredpathThe product's id or slug.Example: fresh-flower-mixed-arrangements
destinationrequiredqueryISO country code from GET /destinations.Example: GB

Request

curl "https://moatdmgiftstore.com/api/v1/products/fresh-flower-mixed-arrangements?destination=GB" \
  -H "Authorization: Bearer $MOATDM_API_KEY"

Response · 200

JSON
{
  "data": {
    "id": "6f1c2a90-3c1e-4c55-9a0b-8b1e2f9d4a11",
    "slug": "fresh-flower-mixed-arrangements",
    "name": "Fresh Flower Mixed Arrangements",
    "tagline": "Seasonal blooms, hand-tied",
    "description": "A hand-tied bouquet of the season's freshest blooms.",
    "category": {
      "slug": "flowers",
      "name": "Flowers & Florals"
    },
    "type": "gift",
    "images": [
      "https://moatdmgiftstore.com/api/public/img?src=products%2Fflowers-mixed.jpg&w=1200"
    ],
    "currency": "NGN",
    "price_kobo": 6000000,
    "shop_price_kobo": 6000000,
    "in_stock": true,
    "variants": [
      {
        "id": "v-small",
        "name": "Small",
        "price_kobo": 6000000,
        "shop_price_kobo": 6000000,
        "in_stock": true
      },
      {
        "id": "v-large",
        "name": "Large",
        "price_kobo": 9000000,
        "shop_price_kobo": 9000000,
        "in_stock": true
      }
    ],
    "delivery": {
      "days_min": 1,
      "days_max": 2
    },
    "gift_message": true
  }
}

Can fail with invalid_request, destination_not_served, not_found, rate_limited.

Wallet balance

GET/wallet

Your naira wallet. A test key sees the sandbox play wallet (₦1,000,000 of play money); a live key sees your real balance.

Live top-ups open with orders, in the next release. Until then a live wallet reads 0.

Needs wallet:read, which full-access keys have.

Request

curl https://moatdmgiftstore.com/api/v1/wallet \
  -H "Authorization: Bearer $MOATDM_API_KEY"

Response · 200

JSON
{
  "mode": "test",
  "currency": "NGN",
  "balance_kobo": 100000000
}

Can fail with forbidden_scope, rate_limited.

Errors

A failed call answers with an HTTP status of 400 or more and this shape. Branch on code, show or log message, and quote request_id to support. Every answer also carries the id in the X-Request-Id header.

JSON · 401
{
  "error": {
    "code": "invalid_key",
    "message": "No key matches. Copy it again from your portal; a lost key can't be shown again.",
    "request_id": "req_4f1c09a2b77e3d5c61"
  }
}
CodeStatusWhenWhat to do
missing_key401 UnauthorisedNo Authorization header, or it isn't "Bearer <key>".Send Authorization: Bearer mdm_test_… on every call.
invalid_key401 UnauthorisedThe key doesn't exist or isn't shaped like a MOATDM key.Copy the key again from your portal. Keys are shown once; make a new one if it's lost.
key_revoked401 UnauthorisedThe key was revoked in the portal or by MOATDM.Make a new key in your portal.
partner_not_active403 ForbiddenYour partner account is pending, rejected or suspended.Check your status in the portal, or contact MOATDM partner support.
agreement_required403 ForbiddenA live key was used before the reseller agreement was accepted.Accept the agreement in your portal.
forbidden_scope403 ForbiddenThe key doesn't carry the permission this call needs (for example a read-only key reading the wallet).Use a full-access key, or make one in your portal.
rate_limited429 Too many requestsMore than 120 calls in a minute on one key.Wait the number of seconds in the Retry-After header, then try again.
invalid_request400 Bad requestA parameter is missing or not valid. The message says which.Fix the parameter and send again.
not_found404 Not foundNo product, category or path matches.Check the id or slug; products can leave the catalogue.
destination_not_served400 Bad requestThe destination isn't a country MOATDM delivers to.Use a code from GET /destinations.
internal_error500 Server errorSomething failed on our side.Try again in a moment. If it keeps happening, send the request_id to partner support.

Limits and paging

  • Each key may make 120 calls a minute. Past that, calls answer 429 rate_limited with a Retry-After header in seconds.
  • GET /products pages its answer. Pass page (from 1) and per_page (1 to 100, default 40), and keep asking while has_more is true. total counts every product for that destination.
  • The catalogue changes during the day. Cache it for up to an hour, and check a product again before you sell it.
  • Ignore fields you don't know. We add fields without notice; we never remove or rename one inside version 1.

Orders (next release)

Placing, tracking and cancelling orders through the API comes in the next release, with wallet top-ups. An order will move through these statuses, and each one has a line you can show your customer:

StatusWhat it meansTell your customer
confirmedPaid from your wallet, waiting for MOATDMYour gift order is confirmed.
on_holdMOATDM needs something from youWe're checking a detail on your order.
preparingBeing bought or made readyYour gift is being prepared.
shippedOn its wayYour gift is on its way.
out_for_deliveryWith the courier todayYour gift arrives today.
deliveredDelivered, with the photo when there is oneYour gift has been delivered.
cancelledCancelled, wallet refundedYour order was cancelled and refunded.
refundedMoney returned after the factYour order was refunded.

Versions and changes

This is version 1, at /api/v1. Version 1 only gains things. Anything that would break your app becomes version 2, and we give at least 90 days' notice by email before version 1 changes.

The OpenAPI file describes every call, for Postman, Insomnia or a code generator.

Changelog

  1. 1.0.012 November 2026

    • First release: keys for test and live use, GET /me, /destinations, /categories, /products, /products/{id} and /wallet.
    • The sandbox play wallet holds ₦1,000,000 of play money for every partner.

Support

Partners reach us on WhatsApp at +234 916 786 8390 or by email at support@moatdmgiftstore.com, Monday to Saturday, 9am to 8pm WAT. Send the request_id of the call that went wrong and we can find it in our logs for 30 days.