curl --request POST \
--url https://api.tassyir.io/apps/2026-10/offers/{id}/codes/bulk \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"codes": [
{
"code": "<string>",
"usageLimit": 2
}
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({codes: [{code: '<string>', usageLimit: 2}]})
};
fetch('https://api.tassyir.io/apps/2026-10/offers/{id}/codes/bulk', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": {
"created": 0,
"results": [
{
"code": "<string>",
"outcome": "<string>"
}
]
}
}{
"type": "<string>",
"title": "<string>",
"status": 400,
"detail": "<string>",
"code": "BAD_REQUEST",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 401,
"detail": "<string>",
"code": "APP_TOKEN_INVALID",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 403,
"detail": "<string>",
"code": "OFFER_NOT_OWNED",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 404,
"detail": "<string>",
"code": "NOT_FOUND",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 409,
"detail": "<string>",
"code": "IDEMPOTENCY_KEY_IN_USE",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 413,
"detail": "<string>",
"code": "PAYLOAD_TOO_LARGE",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 415,
"detail": "<string>",
"code": "UNSUPPORTED_MEDIA_TYPE",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 422,
"detail": "<string>",
"code": "IDEMPOTENCY_KEY_REUSED",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 429,
"detail": "<string>",
"code": "BUSINESS_RATE_LIMITED",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 500,
"detail": "<string>",
"code": "INTERNAL_ERROR",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 503,
"detail": "<string>",
"code": "API_BUSY",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}Add up to 250 codes to an offer
One call, at most 250 codes (one per influencer, say). Partial by design: a code with a bad format, a repeat inside the request or one the business already has is reported for THAT entry in results and the others are created; the call is 200 whatever the mix. An app changes, and reads the codes and redemptions of, only the offers its own installation created (ownerInstallationId is set from the token when it creates one). A merchant’s offer, or another app’s, is 403 OFFER_NOT_OWNED; an offer the token cannot see (another business, a store outside the installation’s stores) is 404.
Needs the write_offers scope (permission offers:update).
curl --request POST \
--url https://api.tassyir.io/apps/2026-10/offers/{id}/codes/bulk \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"codes": [
{
"code": "<string>",
"usageLimit": 2
}
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({codes: [{code: '<string>', usageLimit: 2}]})
};
fetch('https://api.tassyir.io/apps/2026-10/offers/{id}/codes/bulk', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"data": {
"created": 0,
"results": [
{
"code": "<string>",
"outcome": "<string>"
}
]
}
}{
"type": "<string>",
"title": "<string>",
"status": 400,
"detail": "<string>",
"code": "BAD_REQUEST",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 401,
"detail": "<string>",
"code": "APP_TOKEN_INVALID",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 403,
"detail": "<string>",
"code": "OFFER_NOT_OWNED",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 404,
"detail": "<string>",
"code": "NOT_FOUND",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 409,
"detail": "<string>",
"code": "IDEMPOTENCY_KEY_IN_USE",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 413,
"detail": "<string>",
"code": "PAYLOAD_TOO_LARGE",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 415,
"detail": "<string>",
"code": "UNSUPPORTED_MEDIA_TYPE",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 422,
"detail": "<string>",
"code": "IDEMPOTENCY_KEY_REUSED",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 429,
"detail": "<string>",
"code": "BUSINESS_RATE_LIMITED",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 500,
"detail": "<string>",
"code": "INTERNAL_ERROR",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}{
"type": "<string>",
"title": "<string>",
"status": 503,
"detail": "<string>",
"code": "API_BUSY",
"docs": "<string>",
"fix": "<string>",
"requestId": "<string>",
"errors": [
"<string>"
]
}Authorizations
An app access token from POST /apps/oauth/token, valid 1 hour. An offline token acts as the app; an online token acts as the app on behalf of one dashboard user (the intersection of both permission sets).
Headers
Makes a write safe to retry: the same key with the same method, path, query and body within 24 hours answers the stored result (Idempotent-Replayed: true) without running the write again. Only a successful answer is stored, so a retry after a failure runs. A key reused for a different request is 422 IDEMPOTENCY_KEY_REUSED; one whose first request still runs is 409 IDEMPOTENCY_KEY_IN_USE.
1 - 255^[\x21-\x7E]+$Path Parameters
A resource id. One this installation cannot read, or a malformed one, is 404 NOT_FOUND.
1Body
1 - 250 elementsShow child attributes
Show child attributes
Response
What each code did.
What a bulk add did. Partial by design: an entry that cannot be created is reported, the others are created.
Show child attributes
Show child attributes