All checks were successful
Build and deploy / Validate source (push) Successful in 4s
Build and deploy / Integration suite on a real stack (push) Successful in 2m18s
Build and deploy / Secret scan and release gate (push) Successful in 5s
Build and deploy / Publish images (push) Successful in 44s
"Verificar conta" on the Mercado Pago card of the Integrations tab runs the read-only account check (whether the token is a test user's, the card methods, how the test card is classified) without a container console. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
66 lines
3.0 KiB
Python
66 lines
3.0 KiB
Python
"""Read-only look at the Mercado Pago account behind MP_ACCESS_TOKEN.
|
|
|
|
python -m app.mercadopago_probe [--bin 503143] [--valor 50]
|
|
|
|
Run from the api container's console (Portainer > Containers > api >
|
|
Console), or with "Verificar conta" on the Kanban's Integrations tab. It creates nothing and charges nothing: it asks Mercado Pago which
|
|
account the token belongs to, which card methods the account accepts, and how
|
|
it classifies a card number's first digits (type, issuer, instalments). That
|
|
is what payment errors such as 10111 (issuer) and 10113 (method excluded by a
|
|
rule) depend on.
|
|
"""
|
|
import argparse
|
|
import os
|
|
import sys
|
|
|
|
import httpx
|
|
|
|
from .core.secrets import load as load_secret_files
|
|
|
|
API = 'https://api.mercadopago.com'
|
|
|
|
|
|
def check(token, bin_='548083', amount='50', transport=None):
|
|
"""The account, its card methods and how a card's first digits are read."""
|
|
http = httpx.Client(base_url=API, timeout=15, transport=transport,
|
|
headers={'Authorization': f'Bearer {token}'})
|
|
result = {'token': 'test' if token.startswith('TEST-') else 'production'}
|
|
me = http.get('/users/me')
|
|
if me.status_code == 200:
|
|
user = me.json()
|
|
tags = user.get('tags') or []
|
|
result['account'] = {'id': user.get('id'), 'nickname': user.get('nickname'),
|
|
'site': user.get('site_id'), 'test_user': 'test_user' in tags, 'tags': tags}
|
|
else:
|
|
result['account'] = {'error': f'HTTP {me.status_code}'}
|
|
methods = http.get('/v1/payment_methods')
|
|
result['cards'] = ([{'id': m.get('id'), 'type': m.get('payment_type_id'), 'status': m.get('status')}
|
|
for m in methods.json() if m.get('payment_type_id') in ('credit_card', 'debit_card')]
|
|
if methods.status_code == 200 else {'error': f'HTTP {methods.status_code}'})
|
|
options = http.get('/v1/payment_methods/installments', params={'bin': bin_, 'amount': amount})
|
|
result['bin'] = ([{'method': o.get('payment_method_id'), 'type': o.get('payment_type_id'),
|
|
'issuer': (o.get('issuer') or {}).get('name'),
|
|
'installments': [c.get('installments') for c in o.get('payer_costs') or []]}
|
|
for o in options.json()]
|
|
if options.status_code == 200 else {'error': f'HTTP {options.status_code} {options.text[:200]}'})
|
|
return result
|
|
|
|
|
|
def main(argv=None):
|
|
parser = argparse.ArgumentParser(prog='python -m app.mercadopago_probe')
|
|
parser.add_argument('--bin', default='548083', help="the card's first six digits")
|
|
parser.add_argument('--valor', default='50', help='amount in reais for the instalment lookup')
|
|
args = parser.parse_args(argv)
|
|
load_secret_files()
|
|
token = os.environ.get('MP_ACCESS_TOKEN', '')
|
|
if not token:
|
|
print('MP_ACCESS_TOKEN is not set in this container.')
|
|
return 1
|
|
import json
|
|
print(json.dumps(check(token, args.bin, args.valor), indent=2, ensure_ascii=False))
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|