{"openapi":"3.1.0","info":{"title":"DealNear Merchant API","version":"1.0.0","description":"Manage your deals and the coupons customers claim from them — for example, redeem coupons straight from your point-of-sale system."},"servers":[{"url":"https://www.dealnear.ca/api/v1","description":"DealNear"}],"security":[{"apiKey":[]}],"tags":[{"name":"Account","description":"The business behind the API key."},{"name":"Coupons","description":"Coupons customers have claimed from your deals."},{"name":"Deals","description":"The offers you publish on DealNear."},{"name":"Reference","description":"IDs used when creating deals."},{"name":"Webhooks","description":"Requests DealNear sends to your endpoints when coupons and deals change."}],"paths":{"/me":{"get":{"tags":["Account"],"operationId":"getMe","x-scope":null,"summary":"Check your API key","description":"Returns the business the key belongs to and the key’s scopes. Use it to test a new key.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Me"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/coupons":{"get":{"tags":["Coupons"],"operationId":"listCoupons","x-scope":"coupons:read","summary":"List coupons","description":"Coupons claimed from any of your deals, newest first. Poll with `updated_since` to sync redemptions and cancellations into your own system.","parameters":[{"name":"status","in":"query","description":"Only coupons in this status: `claimed`, `redeemed` or `cancelled`.","schema":{"$ref":"#/components/schemas/CouponStatus"}},{"name":"deal_id","in":"query","description":"Only coupons for this deal.","schema":{"type":"integer"}},{"name":"updated_since","in":"query","description":"Only coupons claimed, redeemed or cancelled at or after this time (ISO 8601).","schema":{"type":"string","format":"date-time"}},{"name":"per_page","in":"query","description":"Results per page (1–100, default 25).","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"page","in":"query","description":"Page number, starting at 1.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"A page of results.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Coupon"}},"links":{"$ref":"#/components/schemas/PageLinks"},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed. `errors` maps each field to its messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/coupons/{code}":{"get":{"tags":["Coupons"],"operationId":"getCoupon","x-scope":"coupons:read","summary":"Look up a coupon","description":"Check a code before redeeming it, e.g. to show the cashier which deal it is for. `is_usable` tells you whether it can be redeemed right now.","parameters":[{"name":"code","in":"path","required":true,"description":"Coupon code as the customer shows it. Case, spaces and dashes are ignored: `dn7k4mq2xp` works as well as `DN-7K4M-Q2XP`.","schema":{"type":"string","example":"DN-7K4M-Q2XP"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Coupon"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found, or it belongs to another business.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/coupons/{code}/redeem":{"post":{"tags":["Coupons"],"operationId":"redeemCoupon","x-scope":"coupons:redeem","summary":"Redeem a coupon","description":"Marks the coupon as used. Each coupon can be redeemed once; it is safe to retry, because a repeat attempt returns `409` with `error: already_redeemed` and the coupon (including `redeemed_at`).\n\nPossible `error` values on `409`: `already_redeemed`, `coupon_cancelled`, `coupon_expired`.","parameters":[{"name":"code","in":"path","required":true,"description":"Coupon code as the customer shows it. Case, spaces and dashes are ignored: `dn7k4mq2xp` works as well as `DN-7K4M-Q2XP`.","schema":{"type":"string","example":"DN-7K4M-Q2XP"}}],"responses":{"200":{"description":"Redeemed.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Coupon"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found, or it belongs to another business.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The coupon cannot be redeemed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemRefusal"}}}}}}},"/deals":{"get":{"tags":["Deals"],"operationId":"listDeals","x-scope":"deals:read","summary":"List deals","description":"All of your deals, newest first, in every status.","parameters":[{"name":"status","in":"query","description":"Only deals in this status: `pending`, `active`, `rejected` or `paused`.","schema":{"$ref":"#/components/schemas/DealStatus"}},{"name":"per_page","in":"query","description":"Results per page (1–100, default 25).","schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"page","in":"query","description":"Page number, starting at 1.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"A page of results.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Deal"}},"links":{"$ref":"#/components/schemas/PageLinks"},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed. `errors` maps each field to its messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}},"post":{"tags":["Deals"],"operationId":"createDeal","x-scope":"deals:write","summary":"Create a deal","description":"New deals start as `pending` and go live once DealNear has reviewed them. Send JSON, or `multipart/form-data` to include a cover image.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealInput"}},"multipart/form-data":{"schema":{"allOf":[{"$ref":"#/components/schemas/DealInput"},{"type":"object","properties":{"image":{"type":"string","format":"binary","description":"Cover image: PNG, JPG or WebP, up to 4 MB, 1600×1000 recommended."}}}]}}}},"responses":{"201":{"description":"Created; waiting for review.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deal"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed. `errors` maps each field to its messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/deals/{deal}":{"get":{"tags":["Deals"],"operationId":"getDeal","x-scope":"deals:read","summary":"Get a deal","parameters":[{"name":"deal","in":"path","required":true,"description":"Deal ID.","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deal"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found, or it belongs to another business.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Deals"],"operationId":"updateDeal","x-scope":"deals:write","summary":"Update a deal","description":"Replaces the deal with the body you send (send every field, as when creating). Languages you leave out of `content` are removed.\n\nChanging any text, a price or the image sends a live deal back to `pending` for review. Changing dates, quantities or the per-person limit does not.","parameters":[{"name":"deal","in":"path","required":true,"description":"Deal ID.","schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DealInput"}},"multipart/form-data":{"schema":{"allOf":[{"$ref":"#/components/schemas/DealInput"},{"type":"object","properties":{"image":{"type":"string","format":"binary","description":"Cover image: PNG, JPG or WebP, up to 4 MB, 1600×1000 recommended."}}}]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deal"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found, or it belongs to another business.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Validation failed. `errors` maps each field to its messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}}}}},"/deals/{deal}/pause":{"post":{"tags":["Deals"],"operationId":"pauseDeal","x-scope":"deals:write","summary":"Pause a deal","description":"Hides a live deal from customers. Coupons already claimed stay valid. Pausing a paused deal does nothing.","parameters":[{"name":"deal","in":"path","required":true,"description":"Deal ID.","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deal"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found, or it belongs to another business.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Only live deals can be paused (`error: invalid_status`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/deals/{deal}/resume":{"post":{"tags":["Deals"],"operationId":"resumeDeal","x-scope":"deals:write","summary":"Resume a deal","description":"Puts a paused deal back online. Resuming a live deal does nothing.","parameters":[{"name":"deal","in":"path","required":true,"description":"Deal ID.","schema":{"type":"integer"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deal"}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The API key lacks the required scope (`error: missing_scope`), or the business is suspended.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Not found, or it belongs to another business.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Only paused deals can be resumed (`error: invalid_status`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/categories":{"get":{"tags":["Reference"],"operationId":"listCategories","x-scope":null,"summary":"List categories","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Category"}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/cities":{"get":{"tags":["Reference"],"operationId":"listCities","x-scope":null,"summary":"List cities","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/City"}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"coupon.claimed":{"post":{"tags":["Webhooks"],"operationId":"couponClaimedWebhook","summary":"Coupon claimed","description":"A customer claimed a coupon from one of your deals. `data` is the coupon, as returned by `GET /coupons/{code}`.","parameters":[{"name":"DealNear-Signature","in":"header","required":true,"description":"`t=<unix timestamp>,v1=<hex>`: HMAC-SHA256 of `<timestamp>.<raw body>` keyed with your endpoint’s signing secret. See [Verifying signatures](#webhook-signatures).","schema":{"type":"string","example":"t=1760538669,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"}},{"name":"DealNear-Event","in":"header","required":true,"description":"The event type, same as `type` in the body.","schema":{"type":"string","example":"coupon.redeemed"}},{"name":"DealNear-Event-Id","in":"header","required":true,"description":"Same as `id` in the body. Retries keep it, so use it to ignore duplicates.","schema":{"type":"string","example":"evt_01k7jz2q9w3v8x4c5n6m7p8r9t"}},{"name":"DealNear-Delivery","in":"header","required":true,"description":"ID of this delivery in your delivery log.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"coupon.claimed"},"data":{"$ref":"#/components/schemas/Coupon"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx status acknowledges the event; the body is ignored."},"default":{"description":"Any other status, a redirect, or no answer within 10 seconds is a failure and is retried."}}}},"coupon.redeemed":{"post":{"tags":["Webhooks"],"operationId":"couponRedeemedWebhook","summary":"Coupon redeemed","description":"A coupon was redeemed — through the API, or in the merchant center. `data.redeemed_at` says when.","parameters":[{"name":"DealNear-Signature","in":"header","required":true,"description":"`t=<unix timestamp>,v1=<hex>`: HMAC-SHA256 of `<timestamp>.<raw body>` keyed with your endpoint’s signing secret. See [Verifying signatures](#webhook-signatures).","schema":{"type":"string","example":"t=1760538669,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"}},{"name":"DealNear-Event","in":"header","required":true,"description":"The event type, same as `type` in the body.","schema":{"type":"string","example":"coupon.redeemed"}},{"name":"DealNear-Event-Id","in":"header","required":true,"description":"Same as `id` in the body. Retries keep it, so use it to ignore duplicates.","schema":{"type":"string","example":"evt_01k7jz2q9w3v8x4c5n6m7p8r9t"}},{"name":"DealNear-Delivery","in":"header","required":true,"description":"ID of this delivery in your delivery log.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"coupon.redeemed"},"data":{"$ref":"#/components/schemas/Coupon"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx status acknowledges the event; the body is ignored."},"default":{"description":"Any other status, a redirect, or no answer within 10 seconds is a failure and is retried."}}}},"coupon.cancelled":{"post":{"tags":["Webhooks"],"operationId":"couponCancelledWebhook","summary":"Coupon cancelled","description":"The customer gave an unused coupon back. It can no longer be redeemed, and its stock returns to the deal.","parameters":[{"name":"DealNear-Signature","in":"header","required":true,"description":"`t=<unix timestamp>,v1=<hex>`: HMAC-SHA256 of `<timestamp>.<raw body>` keyed with your endpoint’s signing secret. See [Verifying signatures](#webhook-signatures).","schema":{"type":"string","example":"t=1760538669,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"}},{"name":"DealNear-Event","in":"header","required":true,"description":"The event type, same as `type` in the body.","schema":{"type":"string","example":"coupon.redeemed"}},{"name":"DealNear-Event-Id","in":"header","required":true,"description":"Same as `id` in the body. Retries keep it, so use it to ignore duplicates.","schema":{"type":"string","example":"evt_01k7jz2q9w3v8x4c5n6m7p8r9t"}},{"name":"DealNear-Delivery","in":"header","required":true,"description":"ID of this delivery in your delivery log.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"coupon.cancelled"},"data":{"$ref":"#/components/schemas/Coupon"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx status acknowledges the event; the body is ignored."},"default":{"description":"Any other status, a redirect, or no answer within 10 seconds is a failure and is retried."}}}},"deal.approved":{"post":{"tags":["Webhooks"],"operationId":"dealApprovedWebhook","summary":"Deal approved","description":"DealNear approved one of your deals after review. `data` is the deal, as returned by `GET /deals/{deal}`; it is live from `starts_at`.","parameters":[{"name":"DealNear-Signature","in":"header","required":true,"description":"`t=<unix timestamp>,v1=<hex>`: HMAC-SHA256 of `<timestamp>.<raw body>` keyed with your endpoint’s signing secret. See [Verifying signatures](#webhook-signatures).","schema":{"type":"string","example":"t=1760538669,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"}},{"name":"DealNear-Event","in":"header","required":true,"description":"The event type, same as `type` in the body.","schema":{"type":"string","example":"coupon.redeemed"}},{"name":"DealNear-Event-Id","in":"header","required":true,"description":"Same as `id` in the body. Retries keep it, so use it to ignore duplicates.","schema":{"type":"string","example":"evt_01k7jz2q9w3v8x4c5n6m7p8r9t"}},{"name":"DealNear-Delivery","in":"header","required":true,"description":"ID of this delivery in your delivery log.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"deal.approved"},"data":{"$ref":"#/components/schemas/Deal"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx status acknowledges the event; the body is ignored."},"default":{"description":"Any other status, a redirect, or no answer within 10 seconds is a failure and is retried."}}}},"deal.rejected":{"post":{"tags":["Webhooks"],"operationId":"dealRejectedWebhook","summary":"Deal rejected","description":"DealNear rejected one of your deals in review. `data.rejection_reason` explains why; edit the deal to send it back for review.","parameters":[{"name":"DealNear-Signature","in":"header","required":true,"description":"`t=<unix timestamp>,v1=<hex>`: HMAC-SHA256 of `<timestamp>.<raw body>` keyed with your endpoint’s signing secret. See [Verifying signatures](#webhook-signatures).","schema":{"type":"string","example":"t=1760538669,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"}},{"name":"DealNear-Event","in":"header","required":true,"description":"The event type, same as `type` in the body.","schema":{"type":"string","example":"coupon.redeemed"}},{"name":"DealNear-Event-Id","in":"header","required":true,"description":"Same as `id` in the body. Retries keep it, so use it to ignore duplicates.","schema":{"type":"string","example":"evt_01k7jz2q9w3v8x4c5n6m7p8r9t"}},{"name":"DealNear-Delivery","in":"header","required":true,"description":"ID of this delivery in your delivery log.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"deal.rejected"},"data":{"$ref":"#/components/schemas/Deal"}}}]}}}},"responses":{"2XX":{"description":"Any 2xx status acknowledges the event; the body is ignored."},"default":{"description":"Any other status, a redirect, or no answer within 10 seconds is a failure and is retried."}}}},"ping":{"post":{"tags":["Webhooks"],"operationId":"pingWebhook","summary":"Test event","description":"Sent when you click “Send test event” in the merchant center, whatever events the endpoint subscribes to. It is never retried.","parameters":[{"name":"DealNear-Signature","in":"header","required":true,"description":"`t=<unix timestamp>,v1=<hex>`: HMAC-SHA256 of `<timestamp>.<raw body>` keyed with your endpoint’s signing secret. See [Verifying signatures](#webhook-signatures).","schema":{"type":"string","example":"t=1760538669,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"}},{"name":"DealNear-Event","in":"header","required":true,"description":"The event type, same as `type` in the body.","schema":{"type":"string","example":"coupon.redeemed"}},{"name":"DealNear-Event-Id","in":"header","required":true,"description":"Same as `id` in the body. Retries keep it, so use it to ignore duplicates.","schema":{"type":"string","example":"evt_01k7jz2q9w3v8x4c5n6m7p8r9t"}},{"name":"DealNear-Delivery","in":"header","required":true,"description":"ID of this delivery in your delivery log.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WebhookEvent"},{"type":"object","properties":{"type":{"const":"ping"},"data":{"type":"object","properties":{"message":{"type":"string"},"webhook":{"type":"object","properties":{"id":{"type":"integer"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}}}}}}}}]}}}},"responses":{"2XX":{"description":"Any 2xx status acknowledges the event; the body is ignored."},"default":{"description":"Any other status, a redirect, or no answer within 10 seconds is a failure and is retried."}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"dn_…","description":"Create keys in Merchant center → API keys. Send `Authorization: Bearer dn_…` with every request."}},"schemas":{"Locale":{"type":"string","enum":["en","fr","zh_CN","zh_TW"]},"DealStatus":{"type":"string","enum":["pending","active","rejected","paused"],"description":"`pending`: waiting for review. `active`: live. `rejected`: see `rejection_reason`. `paused`: hidden by you."},"CouponStatus":{"type":"string","enum":["claimed","redeemed","cancelled"],"description":"`claimed`: not used yet. `redeemed`: used. `cancelled`: given back by the customer."},"DealText":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"discount_label":{"type":"string","maxLength":40,"example":"20% off"},"description":{"type":"string","maxLength":5000},"fine_print":{"type":["string","null"],"maxLength":2000}}},"DealInput":{"type":"object","required":["locale","content","category_id","city_id","per_user_limit"],"properties":{"locale":{"allOf":[{"$ref":"#/components/schemas/Locale"}],"description":"The language you wrote the deal in. `content` must have `title`, `discount_label` and `description` in this language."},"content":{"type":"object","description":"Deal text keyed by language. Other languages are optional; customers see the original where a translation is missing.","propertyNames":{"$ref":"#/components/schemas/Locale"},"additionalProperties":{"$ref":"#/components/schemas/DealText"},"example":{"en":{"title":"Hot pot for two, 20% off","discount_label":"20% off","description":"Any hot pot set for two people.","fine_print":"Dine-in only."},"zh_CN":{"title":"双人火锅 8 折"}}},"category_id":{"type":"integer","description":"From `GET /categories`."},"city_id":{"type":"integer","description":"From `GET /cities`."},"original_price":{"type":["number","null"],"minimum":0,"description":"Regular price in CAD."},"deal_price":{"type":["number","null"],"minimum":0,"description":"Price with the deal, in CAD. Cannot exceed `original_price`."},"starts_at":{"type":["string","null"],"format":"date-time"},"ends_at":{"type":["string","null"],"format":"date-time","description":"Must be in the future and after `starts_at`. Coupons stop working when the deal ends."},"total_quantity":{"type":["integer","null"],"minimum":1,"description":"How many coupons can be claimed in total; null for unlimited."},"per_user_limit":{"type":"integer","minimum":1,"maximum":20}}},"Deal":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"url":{"type":"string","format":"uri","description":"Public deal page (only visible to customers while `active`)."},"status":{"$ref":"#/components/schemas/DealStatus"},"rejection_reason":{"type":["string","null"]},"is_featured":{"type":"boolean"},"locale":{"$ref":"#/components/schemas/Locale"},"content":{"type":"object","propertyNames":{"$ref":"#/components/schemas/Locale"},"additionalProperties":{"$ref":"#/components/schemas/DealText"}},"category":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"}}},"city":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"}}},"original_price":{"type":["string","null"],"example":"69.99","description":"Decimal string, CAD."},"deal_price":{"type":["string","null"],"example":"47.99","description":"Decimal string, CAD."},"starts_at":{"type":["string","null"],"format":"date-time"},"ends_at":{"type":["string","null"],"format":"date-time"},"total_quantity":{"type":["integer","null"]},"remaining":{"type":["integer","null"],"description":"Coupons left to claim; null when unlimited."},"per_user_limit":{"type":"integer"},"claims_count":{"type":"integer"},"views_count":{"type":"integer"},"image_url":{"type":["string","null"],"format":"uri"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Coupon":{"type":"object","properties":{"code":{"type":"string","example":"DN-7K4M-Q2XP"},"status":{"$ref":"#/components/schemas/CouponStatus"},"is_usable":{"type":"boolean","description":"True when the coupon can be redeemed now."},"deal":{"type":"object","properties":{"id":{"type":"integer"},"title":{"type":"string"},"discount_label":{"type":"string"}}},"customer":{"type":"object","description":"Only the display name is shared.","properties":{"name":{"type":"string"}}},"claimed_at":{"type":"string","format":"date-time"},"redeemed_at":{"type":["string","null"],"format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time","description":"When the deal ends; null for no expiry."},"updated_at":{"type":"string","format":"date-time"}}},"Me":{"type":"object","properties":{"business":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"slug":{"type":"string"},"status":{"type":"string","enum":["pending","approved","suspended"]},"city":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"}}},"url":{"type":["string","null"],"format":"uri"}}},"api_key":{"type":"object","properties":{"name":{"type":"string"},"prefix":{"type":"string","example":"dn_aB3xY9q"},"scopes":{"type":"array","items":{"type":"string","enum":["deals:read","deals:write","coupons:read","coupons:redeem"]}}}}}},"Category":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"names":{"type":"object","propertyNames":{"$ref":"#/components/schemas/Locale"},"additionalProperties":{"type":"string"}}}},"City":{"type":"object","properties":{"id":{"type":"integer"},"slug":{"type":"string"},"province":{"type":"string","example":"ON"},"names":{"type":"object","propertyNames":{"$ref":"#/components/schemas/Locale"},"additionalProperties":{"type":"string"}}}},"PageLinks":{"type":"object","properties":{"first":{"type":["string","null"]},"last":{"type":["string","null"]},"prev":{"type":["string","null"]},"next":{"type":["string","null"],"description":"Follow until null to read every page."}}},"PageMeta":{"type":"object","properties":{"current_page":{"type":"integer"},"last_page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"}}},"Error":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"Human-readable, English."},"error":{"type":"string","description":"Stable machine-readable code, when there is one."}}},"ValidationError":{"type":"object","properties":{"message":{"type":"string"},"errors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}}}},"WebhookEvent":{"type":"object","required":["id","type","created_at","data"],"properties":{"id":{"type":"string","example":"evt_01k7jz2q9w3v8x4c5n6m7p8r9t","description":"Unique per event and the same on every retry."},"type":{"type":"string","enum":["coupon.claimed","coupon.redeemed","coupon.cancelled","deal.approved","deal.rejected","ping"]},"created_at":{"type":"string","format":"date-time","description":"When the event happened. Retries do not change it."},"data":{"type":"object","description":"The coupon or deal as it was when the event happened."}}},"RedeemRefusal":{"type":"object","properties":{"message":{"type":"string"},"error":{"type":"string","enum":["already_redeemed","coupon_cancelled","coupon_expired"]},"data":{"$ref":"#/components/schemas/Coupon"}}}}}}